blob: 2dc14b9da3f9d00ab28374bc5477efece8cde848 [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/*
2 * ARM translation
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 * Copyright (c) 2005-2007 CodeSourcery
6 * Copyright (c) 2007 OpenedHand, Ltd.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
David 'Digit' Turnera5d41202010-05-10 18:37:10 -070019 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080020 */
21#include <stdarg.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <inttypes.h>
26
27#include "cpu.h"
David 'Digit' Turner852088c2013-12-14 23:04:12 +010028#include "exec/exec-all.h"
David 'Digit' Turnercc33b2d2013-12-15 00:09:42 +010029#include "disas/disas.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080030#include "tcg-op.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010031#include "qemu/log.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080032
David 'Digit' Turner52858642011-06-03 13:41:05 +020033#include "helper.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080034#define GEN_HELPER 1
David 'Digit' Turner52858642011-06-03 13:41:05 +020035#include "helper.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080036
David 'Digit' Turner52858642011-06-03 13:41:05 +020037#define ENABLE_ARCH_4T arm_feature(env, ARM_FEATURE_V4T)
38#define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5)
39/* currently all emulated v5 cores are also v5TE, so don't bother */
40#define ENABLE_ARCH_5TE arm_feature(env, ARM_FEATURE_V5)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080041#define ENABLE_ARCH_5J 0
42#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6)
43#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K)
44#define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2)
45#define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7)
46
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070047#define ARCH(x) do { if (!ENABLE_ARCH_##x) goto illegal_op; } while(0)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080048
49/* internal defines */
50typedef struct DisasContext {
51 target_ulong pc;
52 int is_jmp;
53 /* Nonzero if this instruction has been conditionally skipped. */
54 int condjmp;
55 /* The label that will be jumped to when the instruction is skipped. */
56 int condlabel;
57 /* Thumb-2 condtional execution bits. */
58 int condexec_mask;
Vladimir Chtchetkinea1204592010-04-02 11:03:19 -070059 int condexec_cond;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080060 struct TranslationBlock *tb;
61 int singlestep_enabled;
62 int thumb;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080063#if !defined(CONFIG_USER_ONLY)
64 int user;
65#endif
David 'Digit' Turner52858642011-06-03 13:41:05 +020066 int vfp_enabled;
67 int vec_len;
68 int vec_stride;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080069} DisasContext;
70
David 'Digit' Turner86b1fb02014-03-21 15:20:21 +010071static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
David 'Digit' Turner288208c2011-05-11 19:37:35 +020072
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080073#if defined(CONFIG_USER_ONLY)
74#define IS_USER(s) 1
75#else
76#define IS_USER(s) (s->user)
77#endif
78
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080079/* These instructions trap after executing, so defer them until after the
80 conditional executions state has been updated. */
81#define DISAS_WFI 4
82#define DISAS_SWI 5
David 'Digit' Turner52858642011-06-03 13:41:05 +020083#define DISAS_SMC 6
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080084
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070085static TCGv_ptr cpu_env;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080086/* We reuse the same 64-bit temporaries for efficiency. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070087static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
David 'Digit' Turner52858642011-06-03 13:41:05 +020088static TCGv_i32 cpu_R[16];
89static TCGv_i32 cpu_exclusive_addr;
90static TCGv_i32 cpu_exclusive_val;
91static TCGv_i32 cpu_exclusive_high;
92#ifdef CONFIG_USER_ONLY
93static TCGv_i32 cpu_exclusive_test;
94static TCGv_i32 cpu_exclusive_info;
95#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080096
97/* FIXME: These should be removed. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070098static TCGv cpu_F0s, cpu_F1s;
99static TCGv_i64 cpu_F0d, cpu_F1d;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800100
David 'Digit' Turner852088c2013-12-14 23:04:12 +0100101#include "exec/gen-icount.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800102
David 'Digit' Turner52858642011-06-03 13:41:05 +0200103static const char *regnames[] =
104 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
105 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" };
106
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800107/* initialize TCG globals. */
108void arm_translate_init(void)
109{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200110 int i;
111
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700112 cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800113
David 'Digit' Turner52858642011-06-03 13:41:05 +0200114 for (i = 0; i < 16; i++) {
115 cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100116 offsetof(CPUARMState, regs[i]),
David 'Digit' Turner52858642011-06-03 13:41:05 +0200117 regnames[i]);
118 }
119 cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0,
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100120 offsetof(CPUARMState, exclusive_addr), "exclusive_addr");
David 'Digit' Turner52858642011-06-03 13:41:05 +0200121 cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0,
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100122 offsetof(CPUARMState, exclusive_val), "exclusive_val");
David 'Digit' Turner52858642011-06-03 13:41:05 +0200123 cpu_exclusive_high = tcg_global_mem_new_i32(TCG_AREG0,
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100124 offsetof(CPUARMState, exclusive_high), "exclusive_high");
David 'Digit' Turner52858642011-06-03 13:41:05 +0200125#ifdef CONFIG_USER_ONLY
126 cpu_exclusive_test = tcg_global_mem_new_i32(TCG_AREG0,
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100127 offsetof(CPUARMState, exclusive_test), "exclusive_test");
David 'Digit' Turner52858642011-06-03 13:41:05 +0200128 cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100129 offsetof(CPUARMState, exclusive_info), "exclusive_info");
David 'Digit' Turner52858642011-06-03 13:41:05 +0200130#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800131}
132
133static inline TCGv load_cpu_offset(int offset)
134{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200135 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800136 tcg_gen_ld_i32(tmp, cpu_env, offset);
137 return tmp;
138}
139
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100140#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800141
142static inline void store_cpu_offset(TCGv var, int offset)
143{
144 tcg_gen_st_i32(var, cpu_env, offset);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200145 tcg_temp_free_i32(var);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800146}
147
148#define store_cpu_field(var, name) \
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100149 store_cpu_offset(var, offsetof(CPUARMState, name))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800150
151/* Set a variable to the value of a CPU register. */
152static void load_reg_var(DisasContext *s, TCGv var, int reg)
153{
154 if (reg == 15) {
155 uint32_t addr;
156 /* normaly, since we updated PC, we need only to add one insn */
157 if (s->thumb)
158 addr = (long)s->pc + 2;
159 else
160 addr = (long)s->pc + 4;
161 tcg_gen_movi_i32(var, addr);
162 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +0200163 tcg_gen_mov_i32(var, cpu_R[reg]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800164 }
165}
166
167/* Create a new temporary and set it to the value of a CPU register. */
168static inline TCGv load_reg(DisasContext *s, int reg)
169{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200170 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800171 load_reg_var(s, tmp, reg);
172 return tmp;
173}
174
175/* Set a CPU register. The source must be a temporary and will be
176 marked as dead. */
177static void store_reg(DisasContext *s, int reg, TCGv var)
178{
179 if (reg == 15) {
180 tcg_gen_andi_i32(var, var, ~1);
181 s->is_jmp = DISAS_JUMP;
182 }
David 'Digit' Turner52858642011-06-03 13:41:05 +0200183 tcg_gen_mov_i32(cpu_R[reg], var);
184 tcg_temp_free_i32(var);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800185}
186
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800187/* Value extensions. */
188#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
189#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
190#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
191#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)
192
193#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
194#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
195
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800196
David 'Digit' Turner52858642011-06-03 13:41:05 +0200197static inline void gen_set_cpsr(TCGv var, uint32_t mask)
198{
199 TCGv tmp_mask = tcg_const_i32(mask);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +0200200 gen_helper_cpsr_write(cpu_env, var, tmp_mask);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200201 tcg_temp_free_i32(tmp_mask);
202}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800203/* Set NZCV flags from the high 4 bits of var. */
204#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
205
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800206static void gen_exception(int excp)
207{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200208 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800209 tcg_gen_movi_i32(tmp, excp);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +0200210 gen_helper_exception(cpu_env, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200211 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800212}
213
214static void gen_smul_dual(TCGv a, TCGv b)
215{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200216 TCGv tmp1 = tcg_temp_new_i32();
217 TCGv tmp2 = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800218 tcg_gen_ext16s_i32(tmp1, a);
219 tcg_gen_ext16s_i32(tmp2, b);
220 tcg_gen_mul_i32(tmp1, tmp1, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200221 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800222 tcg_gen_sari_i32(a, a, 16);
223 tcg_gen_sari_i32(b, b, 16);
224 tcg_gen_mul_i32(b, b, a);
225 tcg_gen_mov_i32(a, tmp1);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200226 tcg_temp_free_i32(tmp1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800227}
228
229/* Byteswap each halfword. */
230static void gen_rev16(TCGv var)
231{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200232 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800233 tcg_gen_shri_i32(tmp, var, 8);
234 tcg_gen_andi_i32(tmp, tmp, 0x00ff00ff);
235 tcg_gen_shli_i32(var, var, 8);
236 tcg_gen_andi_i32(var, var, 0xff00ff00);
237 tcg_gen_or_i32(var, var, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200238 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800239}
240
241/* Byteswap low halfword and sign extend. */
242static void gen_revsh(TCGv var)
243{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200244 tcg_gen_ext16u_i32(var, var);
245 tcg_gen_bswap16_i32(var, var);
246 tcg_gen_ext16s_i32(var, var);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800247}
248
249/* Unsigned bitfield extract. */
250static void gen_ubfx(TCGv var, int shift, uint32_t mask)
251{
252 if (shift)
253 tcg_gen_shri_i32(var, var, shift);
254 tcg_gen_andi_i32(var, var, mask);
255}
256
257/* Signed bitfield extract. */
258static void gen_sbfx(TCGv var, int shift, int width)
259{
260 uint32_t signbit;
261
262 if (shift)
263 tcg_gen_sari_i32(var, var, shift);
264 if (shift + width < 32) {
265 signbit = 1u << (width - 1);
266 tcg_gen_andi_i32(var, var, (1u << width) - 1);
267 tcg_gen_xori_i32(var, var, signbit);
268 tcg_gen_subi_i32(var, var, signbit);
269 }
270}
271
272/* Bitfield insertion. Insert val into base. Clobbers base and val. */
273static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask)
274{
275 tcg_gen_andi_i32(val, val, mask);
276 tcg_gen_shli_i32(val, val, shift);
277 tcg_gen_andi_i32(base, base, ~(mask << shift));
278 tcg_gen_or_i32(dest, base, val);
279}
280
David 'Digit' Turner52858642011-06-03 13:41:05 +0200281/* Return (b << 32) + a. Mark inputs as dead */
282static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv b)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800283{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200284 TCGv_i64 tmp64 = tcg_temp_new_i64();
285
286 tcg_gen_extu_i32_i64(tmp64, b);
287 tcg_temp_free_i32(b);
288 tcg_gen_shli_i64(tmp64, tmp64, 32);
289 tcg_gen_add_i64(a, tmp64, a);
290
291 tcg_temp_free_i64(tmp64);
292 return a;
293}
294
295/* Return (b << 32) - a. Mark inputs as dead. */
296static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv b)
297{
298 TCGv_i64 tmp64 = tcg_temp_new_i64();
299
300 tcg_gen_extu_i32_i64(tmp64, b);
301 tcg_temp_free_i32(b);
302 tcg_gen_shli_i64(tmp64, tmp64, 32);
303 tcg_gen_sub_i64(a, tmp64, a);
304
305 tcg_temp_free_i64(tmp64);
306 return a;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800307}
308
309/* FIXME: Most targets have native widening multiplication.
310 It would be good to use that instead of a full wide multiply. */
311/* 32x32->64 multiply. Marks inputs as dead. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700312static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800313{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700314 TCGv_i64 tmp1 = tcg_temp_new_i64();
315 TCGv_i64 tmp2 = tcg_temp_new_i64();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800316
317 tcg_gen_extu_i32_i64(tmp1, a);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200318 tcg_temp_free_i32(a);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800319 tcg_gen_extu_i32_i64(tmp2, b);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200320 tcg_temp_free_i32(b);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800321 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200322 tcg_temp_free_i64(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800323 return tmp1;
324}
325
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700326static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800327{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700328 TCGv_i64 tmp1 = tcg_temp_new_i64();
329 TCGv_i64 tmp2 = tcg_temp_new_i64();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800330
331 tcg_gen_ext_i32_i64(tmp1, a);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200332 tcg_temp_free_i32(a);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800333 tcg_gen_ext_i32_i64(tmp2, b);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200334 tcg_temp_free_i32(b);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800335 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200336 tcg_temp_free_i64(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800337 return tmp1;
338}
339
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800340/* Swap low and high halfwords. */
341static void gen_swap_half(TCGv var)
342{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200343 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800344 tcg_gen_shri_i32(tmp, var, 16);
345 tcg_gen_shli_i32(var, var, 16);
346 tcg_gen_or_i32(var, var, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200347 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800348}
349
350/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead.
351 tmp = (t0 ^ t1) & 0x8000;
352 t0 &= ~0x8000;
353 t1 &= ~0x8000;
354 t0 = (t0 + t1) ^ tmp;
355 */
356
357static void gen_add16(TCGv t0, TCGv t1)
358{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200359 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800360 tcg_gen_xor_i32(tmp, t0, t1);
361 tcg_gen_andi_i32(tmp, tmp, 0x8000);
362 tcg_gen_andi_i32(t0, t0, ~0x8000);
363 tcg_gen_andi_i32(t1, t1, ~0x8000);
364 tcg_gen_add_i32(t0, t0, t1);
365 tcg_gen_xor_i32(t0, t0, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200366 tcg_temp_free_i32(tmp);
367 tcg_temp_free_i32(t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800368}
369
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100370#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, CF))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800371
372/* Set CF to the top bit of var. */
373static void gen_set_CF_bit31(TCGv var)
374{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200375 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800376 tcg_gen_shri_i32(tmp, var, 31);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700377 gen_set_CF(tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200378 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800379}
380
381/* Set N and Z flags from var. */
382static inline void gen_logic_CC(TCGv var)
383{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100384 tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, NF));
385 tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, ZF));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800386}
387
388/* T0 += T1 + CF. */
David 'Digit' Turner52858642011-06-03 13:41:05 +0200389static void gen_adc(TCGv t0, TCGv t1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800390{
391 TCGv tmp;
David 'Digit' Turner52858642011-06-03 13:41:05 +0200392 tcg_gen_add_i32(t0, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800393 tmp = load_cpu_field(CF);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200394 tcg_gen_add_i32(t0, t0, tmp);
395 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800396}
397
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700398/* dest = T0 + T1 + CF. */
399static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
400{
401 TCGv tmp;
402 tcg_gen_add_i32(dest, t0, t1);
403 tmp = load_cpu_field(CF);
404 tcg_gen_add_i32(dest, dest, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200405 tcg_temp_free_i32(tmp);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700406}
407
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800408/* dest = T0 - T1 + CF - 1. */
409static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
410{
411 TCGv tmp;
412 tcg_gen_sub_i32(dest, t0, t1);
413 tmp = load_cpu_field(CF);
414 tcg_gen_add_i32(dest, dest, tmp);
415 tcg_gen_subi_i32(dest, dest, 1);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200416 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800417}
418
419/* FIXME: Implement this natively. */
420#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1)
421
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800422static void shifter_out_im(TCGv var, int shift)
423{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200424 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800425 if (shift == 0) {
426 tcg_gen_andi_i32(tmp, var, 1);
427 } else {
428 tcg_gen_shri_i32(tmp, var, shift);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700429 if (shift != 31)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800430 tcg_gen_andi_i32(tmp, tmp, 1);
431 }
432 gen_set_CF(tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200433 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800434}
435
436/* Shift by immediate. Includes special handling for shift == 0. */
437static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags)
438{
439 switch (shiftop) {
440 case 0: /* LSL */
441 if (shift != 0) {
442 if (flags)
443 shifter_out_im(var, 32 - shift);
444 tcg_gen_shli_i32(var, var, shift);
445 }
446 break;
447 case 1: /* LSR */
448 if (shift == 0) {
449 if (flags) {
450 tcg_gen_shri_i32(var, var, 31);
451 gen_set_CF(var);
452 }
453 tcg_gen_movi_i32(var, 0);
454 } else {
455 if (flags)
456 shifter_out_im(var, shift - 1);
457 tcg_gen_shri_i32(var, var, shift);
458 }
459 break;
460 case 2: /* ASR */
461 if (shift == 0)
462 shift = 32;
463 if (flags)
464 shifter_out_im(var, shift - 1);
465 if (shift == 32)
466 shift = 31;
467 tcg_gen_sari_i32(var, var, shift);
468 break;
469 case 3: /* ROR/RRX */
470 if (shift != 0) {
471 if (flags)
472 shifter_out_im(var, shift - 1);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200473 tcg_gen_rotri_i32(var, var, shift); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800474 } else {
475 TCGv tmp = load_cpu_field(CF);
476 if (flags)
477 shifter_out_im(var, 0);
478 tcg_gen_shri_i32(var, var, 1);
479 tcg_gen_shli_i32(tmp, tmp, 31);
480 tcg_gen_or_i32(var, var, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200481 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800482 }
483 }
484};
485
486static inline void gen_arm_shift_reg(TCGv var, int shiftop,
487 TCGv shift, int flags)
488{
489 if (flags) {
490 switch (shiftop) {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +0200491 case 0: gen_helper_shl_cc(var, cpu_env, var, shift); break;
492 case 1: gen_helper_shr_cc(var, cpu_env, var, shift); break;
493 case 2: gen_helper_sar_cc(var, cpu_env, var, shift); break;
494 case 3: gen_helper_ror_cc(var, cpu_env, var, shift); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800495 }
496 } else {
497 switch (shiftop) {
498 case 0: gen_helper_shl(var, var, shift); break;
499 case 1: gen_helper_shr(var, var, shift); break;
500 case 2: gen_helper_sar(var, var, shift); break;
David 'Digit' Turner52858642011-06-03 13:41:05 +0200501 case 3: tcg_gen_andi_i32(shift, shift, 0x1f);
502 tcg_gen_rotr_i32(var, var, shift); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800503 }
504 }
David 'Digit' Turner52858642011-06-03 13:41:05 +0200505 tcg_temp_free_i32(shift);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800506}
507
508#define PAS_OP(pfx) \
509 switch (op2) { \
510 case 0: gen_pas_helper(glue(pfx,add16)); break; \
511 case 1: gen_pas_helper(glue(pfx,addsubx)); break; \
512 case 2: gen_pas_helper(glue(pfx,subaddx)); break; \
513 case 3: gen_pas_helper(glue(pfx,sub16)); break; \
514 case 4: gen_pas_helper(glue(pfx,add8)); break; \
515 case 7: gen_pas_helper(glue(pfx,sub8)); break; \
516 }
517static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
518{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700519 TCGv_ptr tmp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800520
521 switch (op1) {
522#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
523 case 1:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700524 tmp = tcg_temp_new_ptr();
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100525 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800526 PAS_OP(s)
David 'Digit' Turner52858642011-06-03 13:41:05 +0200527 tcg_temp_free_ptr(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800528 break;
529 case 5:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700530 tmp = tcg_temp_new_ptr();
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100531 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800532 PAS_OP(u)
David 'Digit' Turner52858642011-06-03 13:41:05 +0200533 tcg_temp_free_ptr(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800534 break;
535#undef gen_pas_helper
536#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
537 case 2:
538 PAS_OP(q);
539 break;
540 case 3:
541 PAS_OP(sh);
542 break;
543 case 6:
544 PAS_OP(uq);
545 break;
546 case 7:
547 PAS_OP(uh);
548 break;
549#undef gen_pas_helper
550 }
551}
552#undef PAS_OP
553
554/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */
555#define PAS_OP(pfx) \
David 'Digit' Turner52858642011-06-03 13:41:05 +0200556 switch (op1) { \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800557 case 0: gen_pas_helper(glue(pfx,add8)); break; \
558 case 1: gen_pas_helper(glue(pfx,add16)); break; \
559 case 2: gen_pas_helper(glue(pfx,addsubx)); break; \
560 case 4: gen_pas_helper(glue(pfx,sub8)); break; \
561 case 5: gen_pas_helper(glue(pfx,sub16)); break; \
562 case 6: gen_pas_helper(glue(pfx,subaddx)); break; \
563 }
564static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
565{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700566 TCGv_ptr tmp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800567
David 'Digit' Turner52858642011-06-03 13:41:05 +0200568 switch (op2) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800569#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
570 case 0:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700571 tmp = tcg_temp_new_ptr();
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100572 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800573 PAS_OP(s)
David 'Digit' Turner52858642011-06-03 13:41:05 +0200574 tcg_temp_free_ptr(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800575 break;
576 case 4:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700577 tmp = tcg_temp_new_ptr();
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100578 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800579 PAS_OP(u)
David 'Digit' Turner52858642011-06-03 13:41:05 +0200580 tcg_temp_free_ptr(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800581 break;
582#undef gen_pas_helper
583#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
584 case 1:
585 PAS_OP(q);
586 break;
587 case 2:
588 PAS_OP(sh);
589 break;
590 case 5:
591 PAS_OP(uq);
592 break;
593 case 6:
594 PAS_OP(uh);
595 break;
596#undef gen_pas_helper
597 }
598}
599#undef PAS_OP
600
601static void gen_test_cc(int cc, int label)
602{
603 TCGv tmp;
604 TCGv tmp2;
605 int inv;
606
607 switch (cc) {
608 case 0: /* eq: Z */
609 tmp = load_cpu_field(ZF);
610 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
611 break;
612 case 1: /* ne: !Z */
613 tmp = load_cpu_field(ZF);
614 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
615 break;
616 case 2: /* cs: C */
617 tmp = load_cpu_field(CF);
618 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
619 break;
620 case 3: /* cc: !C */
621 tmp = load_cpu_field(CF);
622 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
623 break;
624 case 4: /* mi: N */
625 tmp = load_cpu_field(NF);
626 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
627 break;
628 case 5: /* pl: !N */
629 tmp = load_cpu_field(NF);
630 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
631 break;
632 case 6: /* vs: V */
633 tmp = load_cpu_field(VF);
634 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
635 break;
636 case 7: /* vc: !V */
637 tmp = load_cpu_field(VF);
638 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
639 break;
640 case 8: /* hi: C && !Z */
641 inv = gen_new_label();
642 tmp = load_cpu_field(CF);
643 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200644 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800645 tmp = load_cpu_field(ZF);
646 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
647 gen_set_label(inv);
648 break;
649 case 9: /* ls: !C || Z */
650 tmp = load_cpu_field(CF);
651 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200652 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800653 tmp = load_cpu_field(ZF);
654 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
655 break;
656 case 10: /* ge: N == V -> N ^ V == 0 */
657 tmp = load_cpu_field(VF);
658 tmp2 = load_cpu_field(NF);
659 tcg_gen_xor_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200660 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800661 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
662 break;
663 case 11: /* lt: N != V -> N ^ V != 0 */
664 tmp = load_cpu_field(VF);
665 tmp2 = load_cpu_field(NF);
666 tcg_gen_xor_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200667 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800668 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
669 break;
670 case 12: /* gt: !Z && N == V */
671 inv = gen_new_label();
672 tmp = load_cpu_field(ZF);
673 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200674 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800675 tmp = load_cpu_field(VF);
676 tmp2 = load_cpu_field(NF);
677 tcg_gen_xor_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200678 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800679 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
680 gen_set_label(inv);
681 break;
682 case 13: /* le: Z || N != V */
683 tmp = load_cpu_field(ZF);
684 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200685 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800686 tmp = load_cpu_field(VF);
687 tmp2 = load_cpu_field(NF);
688 tcg_gen_xor_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200689 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800690 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
691 break;
692 default:
693 fprintf(stderr, "Bad condition code 0x%x\n", cc);
694 abort();
695 }
David 'Digit' Turner52858642011-06-03 13:41:05 +0200696 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800697}
698
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700699static const uint8_t table_logic_cc[16] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800700 1, /* and */
701 1, /* xor */
702 0, /* sub */
703 0, /* rsb */
704 0, /* add */
705 0, /* adc */
706 0, /* sbc */
707 0, /* rsc */
708 1, /* andl */
709 1, /* xorl */
710 0, /* cmp */
711 0, /* cmn */
712 1, /* orr */
713 1, /* mov */
714 1, /* bic */
715 1, /* mvn */
716};
717
718/* Set PC and Thumb state from an immediate address. */
719static inline void gen_bx_im(DisasContext *s, uint32_t addr)
720{
721 TCGv tmp;
722
723 s->is_jmp = DISAS_UPDATE;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800724 if (s->thumb != (addr & 1)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +0200725 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800726 tcg_gen_movi_i32(tmp, addr & 1);
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100727 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, thumb));
David 'Digit' Turner52858642011-06-03 13:41:05 +0200728 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800729 }
David 'Digit' Turner52858642011-06-03 13:41:05 +0200730 tcg_gen_movi_i32(cpu_R[15], addr & ~1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800731}
732
733/* Set PC and Thumb state from var. var is marked as dead. */
734static inline void gen_bx(DisasContext *s, TCGv var)
735{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800736 s->is_jmp = DISAS_UPDATE;
David 'Digit' Turner52858642011-06-03 13:41:05 +0200737 tcg_gen_andi_i32(cpu_R[15], var, ~1);
738 tcg_gen_andi_i32(var, var, 1);
739 store_cpu_field(var, thumb);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800740}
741
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700742/* Variant of store_reg which uses branch&exchange logic when storing
743 to r15 in ARM architecture v7 and above. The source must be a temporary
744 and will be marked as dead. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100745static inline void store_reg_bx(CPUARMState *env, DisasContext *s,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700746 int reg, TCGv var)
747{
748 if (reg == 15 && ENABLE_ARCH_7) {
749 gen_bx(s, var);
750 } else {
751 store_reg(s, reg, var);
752 }
753}
754
David 'Digit' Turner52858642011-06-03 13:41:05 +0200755/* Variant of store_reg which uses branch&exchange logic when storing
756 * to r15 in ARM architecture v5T and above. This is used for storing
757 * the results of a LDR/LDM/POP into r15, and corresponds to the cases
758 * in the ARM ARM which use the LoadWritePC() pseudocode function. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100759static inline void store_reg_from_load(CPUARMState *env, DisasContext *s,
David 'Digit' Turner52858642011-06-03 13:41:05 +0200760 int reg, TCGv var)
761{
762 if (reg == 15 && ENABLE_ARCH_5) {
763 gen_bx(s, var);
764 } else {
765 store_reg(s, reg, var);
766 }
767}
768
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100769static inline void gen_smc(CPUARMState *env, DisasContext *s)
David 'Digit' Turner52858642011-06-03 13:41:05 +0200770{
771 tcg_gen_movi_i32(cpu_R[15], s->pc);
772 s->is_jmp = DISAS_SMC;
773}
774
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800775static inline TCGv gen_ld8s(TCGv addr, int index)
776{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200777 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800778 tcg_gen_qemu_ld8s(tmp, addr, index);
779 return tmp;
780}
781static inline TCGv gen_ld8u(TCGv addr, int index)
782{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200783 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800784 tcg_gen_qemu_ld8u(tmp, addr, index);
785 return tmp;
786}
787static inline TCGv gen_ld16s(TCGv addr, int index)
788{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200789 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800790 tcg_gen_qemu_ld16s(tmp, addr, index);
791 return tmp;
792}
793static inline TCGv gen_ld16u(TCGv addr, int index)
794{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200795 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800796 tcg_gen_qemu_ld16u(tmp, addr, index);
797 return tmp;
798}
799static inline TCGv gen_ld32(TCGv addr, int index)
800{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200801 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800802 tcg_gen_qemu_ld32u(tmp, addr, index);
803 return tmp;
804}
David 'Digit' Turner52858642011-06-03 13:41:05 +0200805static inline TCGv_i64 gen_ld64(TCGv addr, int index)
806{
807 TCGv_i64 tmp = tcg_temp_new_i64();
808 tcg_gen_qemu_ld64(tmp, addr, index);
809 return tmp;
810}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800811static inline void gen_st8(TCGv val, TCGv addr, int index)
812{
813 tcg_gen_qemu_st8(val, addr, index);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200814 tcg_temp_free_i32(val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800815}
816static inline void gen_st16(TCGv val, TCGv addr, int index)
817{
818 tcg_gen_qemu_st16(val, addr, index);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200819 tcg_temp_free_i32(val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800820}
821static inline void gen_st32(TCGv val, TCGv addr, int index)
822{
823 tcg_gen_qemu_st32(val, addr, index);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200824 tcg_temp_free_i32(val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800825}
David 'Digit' Turner52858642011-06-03 13:41:05 +0200826static inline void gen_st64(TCGv_i64 val, TCGv addr, int index)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800827{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200828 tcg_gen_qemu_st64(val, addr, index);
829 tcg_temp_free_i64(val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800830}
831
832static inline void gen_set_pc_im(uint32_t val)
833{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200834 tcg_gen_movi_i32(cpu_R[15], val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800835}
836
837/* Force a TB lookup after an instruction that changes the CPU state. */
838static inline void gen_lookup_tb(DisasContext *s)
839{
David 'Digit' Turner52858642011-06-03 13:41:05 +0200840 tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800841 s->is_jmp = DISAS_UPDATE;
842}
843
844static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
845 TCGv var)
846{
847 int val, rm, shift, shiftop;
848 TCGv offset;
849
850 if (!(insn & (1 << 25))) {
851 /* immediate */
852 val = insn & 0xfff;
853 if (!(insn & (1 << 23)))
854 val = -val;
855 if (val != 0)
856 tcg_gen_addi_i32(var, var, val);
857 } else {
858 /* shift/register */
859 rm = (insn) & 0xf;
860 shift = (insn >> 7) & 0x1f;
861 shiftop = (insn >> 5) & 3;
862 offset = load_reg(s, rm);
863 gen_arm_shift_im(offset, shiftop, shift, 0);
864 if (!(insn & (1 << 23)))
865 tcg_gen_sub_i32(var, var, offset);
866 else
867 tcg_gen_add_i32(var, var, offset);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200868 tcg_temp_free_i32(offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800869 }
870}
871
872static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
873 int extra, TCGv var)
874{
875 int val, rm;
876 TCGv offset;
877
878 if (insn & (1 << 22)) {
879 /* immediate */
880 val = (insn & 0xf) | ((insn >> 4) & 0xf0);
881 if (!(insn & (1 << 23)))
882 val = -val;
883 val += extra;
884 if (val != 0)
885 tcg_gen_addi_i32(var, var, val);
886 } else {
887 /* register */
888 if (extra)
889 tcg_gen_addi_i32(var, var, extra);
890 rm = (insn) & 0xf;
891 offset = load_reg(s, rm);
892 if (!(insn & (1 << 23)))
893 tcg_gen_sub_i32(var, var, offset);
894 else
895 tcg_gen_add_i32(var, var, offset);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200896 tcg_temp_free_i32(offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800897 }
898}
899
David 'Digit' Turner16998982014-03-18 17:23:07 +0100900static TCGv_ptr get_fpstatus_ptr(int neon)
901{
902 TCGv_ptr statusptr = tcg_temp_new_ptr();
903 int offset;
904 if (neon) {
905 offset = offsetof(CPUARMState, vfp.standard_fp_status);
906 } else {
907 offset = offsetof(CPUARMState, vfp.fp_status);
908 }
909 tcg_gen_addi_ptr(statusptr, cpu_env, offset);
910 return statusptr;
911}
912
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800913#define VFP_OP2(name) \
914static inline void gen_vfp_##name(int dp) \
915{ \
David 'Digit' Turner16998982014-03-18 17:23:07 +0100916 TCGv_ptr fpst = get_fpstatus_ptr(0); \
917 if (dp) { \
918 gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, fpst); \
919 } else { \
920 gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, fpst); \
921 } \
922 tcg_temp_free_ptr(fpst); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800923}
924
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800925VFP_OP2(add)
926VFP_OP2(sub)
927VFP_OP2(mul)
928VFP_OP2(div)
929
930#undef VFP_OP2
931
David 'Digit' Turner52858642011-06-03 13:41:05 +0200932static inline void gen_vfp_F1_mul(int dp)
933{
934 /* Like gen_vfp_mul() but put result in F1 */
David 'Digit' Turner16998982014-03-18 17:23:07 +0100935 TCGv_ptr fpst = get_fpstatus_ptr(0);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200936 if (dp) {
David 'Digit' Turner16998982014-03-18 17:23:07 +0100937 gen_helper_vfp_muld(cpu_F1d, cpu_F0d, cpu_F1d, fpst);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200938 } else {
David 'Digit' Turner16998982014-03-18 17:23:07 +0100939 gen_helper_vfp_muls(cpu_F1s, cpu_F0s, cpu_F1s, fpst);
David 'Digit' Turner52858642011-06-03 13:41:05 +0200940 }
941}
942
943static inline void gen_vfp_F1_neg(int dp)
944{
945 /* Like gen_vfp_neg() but put result in F1 */
946 if (dp) {
947 gen_helper_vfp_negd(cpu_F1d, cpu_F0d);
948 } else {
949 gen_helper_vfp_negs(cpu_F1s, cpu_F0s);
950 }
951}
952
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800953static inline void gen_vfp_abs(int dp)
954{
955 if (dp)
956 gen_helper_vfp_absd(cpu_F0d, cpu_F0d);
957 else
958 gen_helper_vfp_abss(cpu_F0s, cpu_F0s);
959}
960
961static inline void gen_vfp_neg(int dp)
962{
963 if (dp)
964 gen_helper_vfp_negd(cpu_F0d, cpu_F0d);
965 else
966 gen_helper_vfp_negs(cpu_F0s, cpu_F0s);
967}
968
969static inline void gen_vfp_sqrt(int dp)
970{
971 if (dp)
972 gen_helper_vfp_sqrtd(cpu_F0d, cpu_F0d, cpu_env);
973 else
974 gen_helper_vfp_sqrts(cpu_F0s, cpu_F0s, cpu_env);
975}
976
977static inline void gen_vfp_cmp(int dp)
978{
979 if (dp)
980 gen_helper_vfp_cmpd(cpu_F0d, cpu_F1d, cpu_env);
981 else
982 gen_helper_vfp_cmps(cpu_F0s, cpu_F1s, cpu_env);
983}
984
985static inline void gen_vfp_cmpe(int dp)
986{
987 if (dp)
988 gen_helper_vfp_cmped(cpu_F0d, cpu_F1d, cpu_env);
989 else
990 gen_helper_vfp_cmpes(cpu_F0s, cpu_F1s, cpu_env);
991}
992
993static inline void gen_vfp_F1_ld0(int dp)
994{
995 if (dp)
996 tcg_gen_movi_i64(cpu_F1d, 0);
997 else
998 tcg_gen_movi_i32(cpu_F1s, 0);
999}
1000
David 'Digit' Turner52858642011-06-03 13:41:05 +02001001#define VFP_GEN_ITOF(name) \
1002static inline void gen_vfp_##name(int dp, int neon) \
1003{ \
David 'Digit' Turner16998982014-03-18 17:23:07 +01001004 TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
David 'Digit' Turner52858642011-06-03 13:41:05 +02001005 if (dp) { \
1006 gen_helper_vfp_##name##d(cpu_F0d, cpu_F0s, statusptr); \
1007 } else { \
1008 gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
1009 } \
1010 tcg_temp_free_ptr(statusptr); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001011}
1012
David 'Digit' Turner52858642011-06-03 13:41:05 +02001013VFP_GEN_ITOF(uito)
1014VFP_GEN_ITOF(sito)
1015#undef VFP_GEN_ITOF
1016
1017#define VFP_GEN_FTOI(name) \
1018static inline void gen_vfp_##name(int dp, int neon) \
1019{ \
David 'Digit' Turner16998982014-03-18 17:23:07 +01001020 TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
David 'Digit' Turner52858642011-06-03 13:41:05 +02001021 if (dp) { \
1022 gen_helper_vfp_##name##d(cpu_F0s, cpu_F0d, statusptr); \
1023 } else { \
1024 gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
1025 } \
1026 tcg_temp_free_ptr(statusptr); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001027}
1028
David 'Digit' Turner52858642011-06-03 13:41:05 +02001029VFP_GEN_FTOI(toui)
1030VFP_GEN_FTOI(touiz)
1031VFP_GEN_FTOI(tosi)
1032VFP_GEN_FTOI(tosiz)
1033#undef VFP_GEN_FTOI
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001034
1035#define VFP_GEN_FIX(name) \
David 'Digit' Turner52858642011-06-03 13:41:05 +02001036static inline void gen_vfp_##name(int dp, int shift, int neon) \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001037{ \
David 'Digit' Turner52858642011-06-03 13:41:05 +02001038 TCGv tmp_shift = tcg_const_i32(shift); \
David 'Digit' Turner16998982014-03-18 17:23:07 +01001039 TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
David 'Digit' Turner52858642011-06-03 13:41:05 +02001040 if (dp) { \
1041 gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tmp_shift, statusptr); \
1042 } else { \
1043 gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tmp_shift, statusptr); \
1044 } \
1045 tcg_temp_free_i32(tmp_shift); \
1046 tcg_temp_free_ptr(statusptr); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001047}
1048VFP_GEN_FIX(tosh)
1049VFP_GEN_FIX(tosl)
1050VFP_GEN_FIX(touh)
1051VFP_GEN_FIX(toul)
1052VFP_GEN_FIX(shto)
1053VFP_GEN_FIX(slto)
1054VFP_GEN_FIX(uhto)
1055VFP_GEN_FIX(ulto)
1056#undef VFP_GEN_FIX
1057
David 'Digit' Turner52858642011-06-03 13:41:05 +02001058static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001059{
1060 if (dp)
David 'Digit' Turner52858642011-06-03 13:41:05 +02001061 tcg_gen_qemu_ld64(cpu_F0d, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001062 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02001063 tcg_gen_qemu_ld32u(cpu_F0s, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001064}
1065
David 'Digit' Turner52858642011-06-03 13:41:05 +02001066static inline void gen_vfp_st(DisasContext *s, int dp, TCGv addr)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001067{
1068 if (dp)
David 'Digit' Turner52858642011-06-03 13:41:05 +02001069 tcg_gen_qemu_st64(cpu_F0d, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001070 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02001071 tcg_gen_qemu_st32(cpu_F0s, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001072}
1073
1074static inline long
1075vfp_reg_offset (int dp, int reg)
1076{
1077 if (dp)
1078 return offsetof(CPUARMState, vfp.regs[reg]);
1079 else if (reg & 1) {
1080 return offsetof(CPUARMState, vfp.regs[reg >> 1])
1081 + offsetof(CPU_DoubleU, l.upper);
1082 } else {
1083 return offsetof(CPUARMState, vfp.regs[reg >> 1])
1084 + offsetof(CPU_DoubleU, l.lower);
1085 }
1086}
1087
1088/* Return the offset of a 32-bit piece of a NEON register.
1089 zero is the least significant end of the register. */
1090static inline long
1091neon_reg_offset (int reg, int n)
1092{
1093 int sreg;
1094 sreg = reg * 2 + n;
1095 return vfp_reg_offset(0, sreg);
1096}
1097
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001098static TCGv neon_load_reg(int reg, int pass)
1099{
David 'Digit' Turner52858642011-06-03 13:41:05 +02001100 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001101 tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass));
1102 return tmp;
1103}
1104
1105static void neon_store_reg(int reg, int pass, TCGv var)
1106{
1107 tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass));
David 'Digit' Turner52858642011-06-03 13:41:05 +02001108 tcg_temp_free_i32(var);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001109}
1110
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001111static inline void neon_load_reg64(TCGv_i64 var, int reg)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001112{
1113 tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
1114}
1115
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001116static inline void neon_store_reg64(TCGv_i64 var, int reg)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001117{
1118 tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
1119}
1120
1121#define tcg_gen_ld_f32 tcg_gen_ld_i32
1122#define tcg_gen_ld_f64 tcg_gen_ld_i64
1123#define tcg_gen_st_f32 tcg_gen_st_i32
1124#define tcg_gen_st_f64 tcg_gen_st_i64
1125
1126static inline void gen_mov_F0_vreg(int dp, int reg)
1127{
1128 if (dp)
1129 tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
1130 else
1131 tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
1132}
1133
1134static inline void gen_mov_F1_vreg(int dp, int reg)
1135{
1136 if (dp)
1137 tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
1138 else
1139 tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
1140}
1141
1142static inline void gen_mov_vreg_F0(int dp, int reg)
1143{
1144 if (dp)
1145 tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
1146 else
1147 tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
1148}
1149
1150#define ARM_CP_RW_BIT (1 << 20)
1151
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001152static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001153{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001154 tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001155}
1156
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001157static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001158{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001159 tcg_gen_st_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001160}
1161
David 'Digit' Turner52858642011-06-03 13:41:05 +02001162static inline TCGv iwmmxt_load_creg(int reg)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001163{
David 'Digit' Turner52858642011-06-03 13:41:05 +02001164 TCGv var = tcg_temp_new_i32();
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001165 tcg_gen_ld_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg]));
David 'Digit' Turner52858642011-06-03 13:41:05 +02001166 return var;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001167}
1168
David 'Digit' Turner52858642011-06-03 13:41:05 +02001169static inline void iwmmxt_store_creg(int reg, TCGv var)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001170{
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001171 tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg]));
David 'Digit' Turner52858642011-06-03 13:41:05 +02001172 tcg_temp_free_i32(var);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001173}
1174
1175static inline void gen_op_iwmmxt_movq_wRn_M0(int rn)
1176{
1177 iwmmxt_store_reg(cpu_M0, rn);
1178}
1179
1180static inline void gen_op_iwmmxt_movq_M0_wRn(int rn)
1181{
1182 iwmmxt_load_reg(cpu_M0, rn);
1183}
1184
1185static inline void gen_op_iwmmxt_orq_M0_wRn(int rn)
1186{
1187 iwmmxt_load_reg(cpu_V1, rn);
1188 tcg_gen_or_i64(cpu_M0, cpu_M0, cpu_V1);
1189}
1190
1191static inline void gen_op_iwmmxt_andq_M0_wRn(int rn)
1192{
1193 iwmmxt_load_reg(cpu_V1, rn);
1194 tcg_gen_and_i64(cpu_M0, cpu_M0, cpu_V1);
1195}
1196
1197static inline void gen_op_iwmmxt_xorq_M0_wRn(int rn)
1198{
1199 iwmmxt_load_reg(cpu_V1, rn);
1200 tcg_gen_xor_i64(cpu_M0, cpu_M0, cpu_V1);
1201}
1202
1203#define IWMMXT_OP(name) \
1204static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
1205{ \
1206 iwmmxt_load_reg(cpu_V1, rn); \
1207 gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \
1208}
1209
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02001210#define IWMMXT_OP_ENV(name) \
1211static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
1212{ \
1213 iwmmxt_load_reg(cpu_V1, rn); \
1214 gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \
1215}
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001216
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02001217#define IWMMXT_OP_ENV_SIZE(name) \
1218IWMMXT_OP_ENV(name##b) \
1219IWMMXT_OP_ENV(name##w) \
1220IWMMXT_OP_ENV(name##l)
1221
1222#define IWMMXT_OP_ENV1(name) \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001223static inline void gen_op_iwmmxt_##name##_M0(void) \
1224{ \
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02001225 gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001226}
1227
1228IWMMXT_OP(maddsq)
1229IWMMXT_OP(madduq)
1230IWMMXT_OP(sadb)
1231IWMMXT_OP(sadw)
1232IWMMXT_OP(mulslw)
1233IWMMXT_OP(mulshw)
1234IWMMXT_OP(mululw)
1235IWMMXT_OP(muluhw)
1236IWMMXT_OP(macsw)
1237IWMMXT_OP(macuw)
1238
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02001239IWMMXT_OP_ENV_SIZE(unpackl)
1240IWMMXT_OP_ENV_SIZE(unpackh)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001241
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02001242IWMMXT_OP_ENV1(unpacklub)
1243IWMMXT_OP_ENV1(unpackluw)
1244IWMMXT_OP_ENV1(unpacklul)
1245IWMMXT_OP_ENV1(unpackhub)
1246IWMMXT_OP_ENV1(unpackhuw)
1247IWMMXT_OP_ENV1(unpackhul)
1248IWMMXT_OP_ENV1(unpacklsb)
1249IWMMXT_OP_ENV1(unpacklsw)
1250IWMMXT_OP_ENV1(unpacklsl)
1251IWMMXT_OP_ENV1(unpackhsb)
1252IWMMXT_OP_ENV1(unpackhsw)
1253IWMMXT_OP_ENV1(unpackhsl)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001254
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02001255IWMMXT_OP_ENV_SIZE(cmpeq)
1256IWMMXT_OP_ENV_SIZE(cmpgtu)
1257IWMMXT_OP_ENV_SIZE(cmpgts)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001258
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02001259IWMMXT_OP_ENV_SIZE(mins)
1260IWMMXT_OP_ENV_SIZE(minu)
1261IWMMXT_OP_ENV_SIZE(maxs)
1262IWMMXT_OP_ENV_SIZE(maxu)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001263
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02001264IWMMXT_OP_ENV_SIZE(subn)
1265IWMMXT_OP_ENV_SIZE(addn)
1266IWMMXT_OP_ENV_SIZE(subu)
1267IWMMXT_OP_ENV_SIZE(addu)
1268IWMMXT_OP_ENV_SIZE(subs)
1269IWMMXT_OP_ENV_SIZE(adds)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001270
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02001271IWMMXT_OP_ENV(avgb0)
1272IWMMXT_OP_ENV(avgb1)
1273IWMMXT_OP_ENV(avgw0)
1274IWMMXT_OP_ENV(avgw1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001275
1276IWMMXT_OP(msadb)
1277
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02001278IWMMXT_OP_ENV(packuw)
1279IWMMXT_OP_ENV(packul)
1280IWMMXT_OP_ENV(packuq)
1281IWMMXT_OP_ENV(packsw)
1282IWMMXT_OP_ENV(packsl)
1283IWMMXT_OP_ENV(packsq)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001284
1285static void gen_op_iwmmxt_set_mup(void)
1286{
1287 TCGv tmp;
1288 tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
1289 tcg_gen_ori_i32(tmp, tmp, 2);
1290 store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
1291}
1292
1293static void gen_op_iwmmxt_set_cup(void)
1294{
1295 TCGv tmp;
1296 tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
1297 tcg_gen_ori_i32(tmp, tmp, 1);
1298 store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
1299}
1300
1301static void gen_op_iwmmxt_setpsr_nz(void)
1302{
David 'Digit' Turner52858642011-06-03 13:41:05 +02001303 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001304 gen_helper_iwmmxt_setpsr_nz(tmp, cpu_M0);
1305 store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCASF]);
1306}
1307
1308static inline void gen_op_iwmmxt_addl_M0_wRn(int rn)
1309{
1310 iwmmxt_load_reg(cpu_V1, rn);
1311 tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
1312 tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1313}
1314
David 'Digit' Turner52858642011-06-03 13:41:05 +02001315static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn, TCGv dest)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001316{
1317 int rd;
1318 uint32_t offset;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001319 TCGv tmp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001320
1321 rd = (insn >> 16) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001322 tmp = load_reg(s, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001323
1324 offset = (insn & 0xff) << ((insn >> 7) & 2);
1325 if (insn & (1 << 24)) {
1326 /* Pre indexed */
1327 if (insn & (1 << 23))
David 'Digit' Turner52858642011-06-03 13:41:05 +02001328 tcg_gen_addi_i32(tmp, tmp, offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001329 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02001330 tcg_gen_addi_i32(tmp, tmp, -offset);
1331 tcg_gen_mov_i32(dest, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001332 if (insn & (1 << 21))
David 'Digit' Turner52858642011-06-03 13:41:05 +02001333 store_reg(s, rd, tmp);
1334 else
1335 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001336 } else if (insn & (1 << 21)) {
1337 /* Post indexed */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001338 tcg_gen_mov_i32(dest, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001339 if (insn & (1 << 23))
David 'Digit' Turner52858642011-06-03 13:41:05 +02001340 tcg_gen_addi_i32(tmp, tmp, offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001341 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02001342 tcg_gen_addi_i32(tmp, tmp, -offset);
1343 store_reg(s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001344 } else if (!(insn & (1 << 23)))
1345 return 1;
1346 return 0;
1347}
1348
David 'Digit' Turner52858642011-06-03 13:41:05 +02001349static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv dest)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001350{
1351 int rd = (insn >> 0) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001352 TCGv tmp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001353
David 'Digit' Turner52858642011-06-03 13:41:05 +02001354 if (insn & (1 << 8)) {
1355 if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001356 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001357 } else {
1358 tmp = iwmmxt_load_creg(rd);
1359 }
1360 } else {
1361 tmp = tcg_temp_new_i32();
1362 iwmmxt_load_reg(cpu_V0, rd);
1363 tcg_gen_trunc_i64_i32(tmp, cpu_V0);
1364 }
1365 tcg_gen_andi_i32(tmp, tmp, mask);
1366 tcg_gen_mov_i32(dest, tmp);
1367 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001368 return 0;
1369}
1370
David 'Digit' Turner52858642011-06-03 13:41:05 +02001371/* Disassemble an iwMMXt instruction. Returns nonzero if an error occurred
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001372 (ie. an undefined instruction). */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01001373static int disas_iwmmxt_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001374{
1375 int rd, wrd;
1376 int rdhi, rdlo, rd0, rd1, i;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001377 TCGv addr;
1378 TCGv tmp, tmp2, tmp3;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001379
1380 if ((insn & 0x0e000e00) == 0x0c000000) {
1381 if ((insn & 0x0fe00ff0) == 0x0c400000) {
1382 wrd = insn & 0xf;
1383 rdlo = (insn >> 12) & 0xf;
1384 rdhi = (insn >> 16) & 0xf;
1385 if (insn & ARM_CP_RW_BIT) { /* TMRRC */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001386 iwmmxt_load_reg(cpu_V0, wrd);
1387 tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0);
1388 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
1389 tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001390 } else { /* TMCRR */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001391 tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
1392 iwmmxt_store_reg(cpu_V0, wrd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001393 gen_op_iwmmxt_set_mup();
1394 }
1395 return 0;
1396 }
1397
1398 wrd = (insn >> 12) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001399 addr = tcg_temp_new_i32();
1400 if (gen_iwmmxt_address(s, insn, addr)) {
1401 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001402 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001403 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001404 if (insn & ARM_CP_RW_BIT) {
1405 if ((insn >> 28) == 0xf) { /* WLDRW wCx */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001406 tmp = tcg_temp_new_i32();
1407 tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
1408 iwmmxt_store_creg(wrd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001409 } else {
1410 i = 1;
1411 if (insn & (1 << 8)) {
1412 if (insn & (1 << 22)) { /* WLDRD */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001413 tcg_gen_qemu_ld64(cpu_M0, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001414 i = 0;
1415 } else { /* WLDRW wRd */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001416 tmp = gen_ld32(addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001417 }
1418 } else {
1419 if (insn & (1 << 22)) { /* WLDRH */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001420 tmp = gen_ld16u(addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001421 } else { /* WLDRB */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001422 tmp = gen_ld8u(addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001423 }
1424 }
1425 if (i) {
1426 tcg_gen_extu_i32_i64(cpu_M0, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02001427 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001428 }
1429 gen_op_iwmmxt_movq_wRn_M0(wrd);
1430 }
1431 } else {
1432 if ((insn >> 28) == 0xf) { /* WSTRW wCx */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001433 tmp = iwmmxt_load_creg(wrd);
1434 gen_st32(tmp, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001435 } else {
1436 gen_op_iwmmxt_movq_M0_wRn(wrd);
David 'Digit' Turner52858642011-06-03 13:41:05 +02001437 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001438 if (insn & (1 << 8)) {
1439 if (insn & (1 << 22)) { /* WSTRD */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001440 tcg_temp_free_i32(tmp);
1441 tcg_gen_qemu_st64(cpu_M0, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001442 } else { /* WSTRW wRd */
1443 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02001444 gen_st32(tmp, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001445 }
1446 } else {
1447 if (insn & (1 << 22)) { /* WSTRH */
1448 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02001449 gen_st16(tmp, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001450 } else { /* WSTRB */
1451 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02001452 gen_st8(tmp, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001453 }
1454 }
1455 }
1456 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02001457 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001458 return 0;
1459 }
1460
1461 if ((insn & 0x0f000000) != 0x0e000000)
1462 return 1;
1463
1464 switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
1465 case 0x000: /* WOR */
1466 wrd = (insn >> 12) & 0xf;
1467 rd0 = (insn >> 0) & 0xf;
1468 rd1 = (insn >> 16) & 0xf;
1469 gen_op_iwmmxt_movq_M0_wRn(rd0);
1470 gen_op_iwmmxt_orq_M0_wRn(rd1);
1471 gen_op_iwmmxt_setpsr_nz();
1472 gen_op_iwmmxt_movq_wRn_M0(wrd);
1473 gen_op_iwmmxt_set_mup();
1474 gen_op_iwmmxt_set_cup();
1475 break;
1476 case 0x011: /* TMCR */
1477 if (insn & 0xf)
1478 return 1;
1479 rd = (insn >> 12) & 0xf;
1480 wrd = (insn >> 16) & 0xf;
1481 switch (wrd) {
1482 case ARM_IWMMXT_wCID:
1483 case ARM_IWMMXT_wCASF:
1484 break;
1485 case ARM_IWMMXT_wCon:
1486 gen_op_iwmmxt_set_cup();
1487 /* Fall through. */
1488 case ARM_IWMMXT_wCSSF:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001489 tmp = iwmmxt_load_creg(wrd);
1490 tmp2 = load_reg(s, rd);
1491 tcg_gen_andc_i32(tmp, tmp, tmp2);
1492 tcg_temp_free_i32(tmp2);
1493 iwmmxt_store_creg(wrd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001494 break;
1495 case ARM_IWMMXT_wCGR0:
1496 case ARM_IWMMXT_wCGR1:
1497 case ARM_IWMMXT_wCGR2:
1498 case ARM_IWMMXT_wCGR3:
1499 gen_op_iwmmxt_set_cup();
David 'Digit' Turner52858642011-06-03 13:41:05 +02001500 tmp = load_reg(s, rd);
1501 iwmmxt_store_creg(wrd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001502 break;
1503 default:
1504 return 1;
1505 }
1506 break;
1507 case 0x100: /* WXOR */
1508 wrd = (insn >> 12) & 0xf;
1509 rd0 = (insn >> 0) & 0xf;
1510 rd1 = (insn >> 16) & 0xf;
1511 gen_op_iwmmxt_movq_M0_wRn(rd0);
1512 gen_op_iwmmxt_xorq_M0_wRn(rd1);
1513 gen_op_iwmmxt_setpsr_nz();
1514 gen_op_iwmmxt_movq_wRn_M0(wrd);
1515 gen_op_iwmmxt_set_mup();
1516 gen_op_iwmmxt_set_cup();
1517 break;
1518 case 0x111: /* TMRC */
1519 if (insn & 0xf)
1520 return 1;
1521 rd = (insn >> 12) & 0xf;
1522 wrd = (insn >> 16) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001523 tmp = iwmmxt_load_creg(wrd);
1524 store_reg(s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001525 break;
1526 case 0x300: /* WANDN */
1527 wrd = (insn >> 12) & 0xf;
1528 rd0 = (insn >> 0) & 0xf;
1529 rd1 = (insn >> 16) & 0xf;
1530 gen_op_iwmmxt_movq_M0_wRn(rd0);
1531 tcg_gen_neg_i64(cpu_M0, cpu_M0);
1532 gen_op_iwmmxt_andq_M0_wRn(rd1);
1533 gen_op_iwmmxt_setpsr_nz();
1534 gen_op_iwmmxt_movq_wRn_M0(wrd);
1535 gen_op_iwmmxt_set_mup();
1536 gen_op_iwmmxt_set_cup();
1537 break;
1538 case 0x200: /* WAND */
1539 wrd = (insn >> 12) & 0xf;
1540 rd0 = (insn >> 0) & 0xf;
1541 rd1 = (insn >> 16) & 0xf;
1542 gen_op_iwmmxt_movq_M0_wRn(rd0);
1543 gen_op_iwmmxt_andq_M0_wRn(rd1);
1544 gen_op_iwmmxt_setpsr_nz();
1545 gen_op_iwmmxt_movq_wRn_M0(wrd);
1546 gen_op_iwmmxt_set_mup();
1547 gen_op_iwmmxt_set_cup();
1548 break;
1549 case 0x810: case 0xa10: /* WMADD */
1550 wrd = (insn >> 12) & 0xf;
1551 rd0 = (insn >> 0) & 0xf;
1552 rd1 = (insn >> 16) & 0xf;
1553 gen_op_iwmmxt_movq_M0_wRn(rd0);
1554 if (insn & (1 << 21))
1555 gen_op_iwmmxt_maddsq_M0_wRn(rd1);
1556 else
1557 gen_op_iwmmxt_madduq_M0_wRn(rd1);
1558 gen_op_iwmmxt_movq_wRn_M0(wrd);
1559 gen_op_iwmmxt_set_mup();
1560 break;
1561 case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */
1562 wrd = (insn >> 12) & 0xf;
1563 rd0 = (insn >> 16) & 0xf;
1564 rd1 = (insn >> 0) & 0xf;
1565 gen_op_iwmmxt_movq_M0_wRn(rd0);
1566 switch ((insn >> 22) & 3) {
1567 case 0:
1568 gen_op_iwmmxt_unpacklb_M0_wRn(rd1);
1569 break;
1570 case 1:
1571 gen_op_iwmmxt_unpacklw_M0_wRn(rd1);
1572 break;
1573 case 2:
1574 gen_op_iwmmxt_unpackll_M0_wRn(rd1);
1575 break;
1576 case 3:
1577 return 1;
1578 }
1579 gen_op_iwmmxt_movq_wRn_M0(wrd);
1580 gen_op_iwmmxt_set_mup();
1581 gen_op_iwmmxt_set_cup();
1582 break;
1583 case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */
1584 wrd = (insn >> 12) & 0xf;
1585 rd0 = (insn >> 16) & 0xf;
1586 rd1 = (insn >> 0) & 0xf;
1587 gen_op_iwmmxt_movq_M0_wRn(rd0);
1588 switch ((insn >> 22) & 3) {
1589 case 0:
1590 gen_op_iwmmxt_unpackhb_M0_wRn(rd1);
1591 break;
1592 case 1:
1593 gen_op_iwmmxt_unpackhw_M0_wRn(rd1);
1594 break;
1595 case 2:
1596 gen_op_iwmmxt_unpackhl_M0_wRn(rd1);
1597 break;
1598 case 3:
1599 return 1;
1600 }
1601 gen_op_iwmmxt_movq_wRn_M0(wrd);
1602 gen_op_iwmmxt_set_mup();
1603 gen_op_iwmmxt_set_cup();
1604 break;
1605 case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */
1606 wrd = (insn >> 12) & 0xf;
1607 rd0 = (insn >> 16) & 0xf;
1608 rd1 = (insn >> 0) & 0xf;
1609 gen_op_iwmmxt_movq_M0_wRn(rd0);
1610 if (insn & (1 << 22))
1611 gen_op_iwmmxt_sadw_M0_wRn(rd1);
1612 else
1613 gen_op_iwmmxt_sadb_M0_wRn(rd1);
1614 if (!(insn & (1 << 20)))
1615 gen_op_iwmmxt_addl_M0_wRn(wrd);
1616 gen_op_iwmmxt_movq_wRn_M0(wrd);
1617 gen_op_iwmmxt_set_mup();
1618 break;
1619 case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */
1620 wrd = (insn >> 12) & 0xf;
1621 rd0 = (insn >> 16) & 0xf;
1622 rd1 = (insn >> 0) & 0xf;
1623 gen_op_iwmmxt_movq_M0_wRn(rd0);
1624 if (insn & (1 << 21)) {
1625 if (insn & (1 << 20))
1626 gen_op_iwmmxt_mulshw_M0_wRn(rd1);
1627 else
1628 gen_op_iwmmxt_mulslw_M0_wRn(rd1);
1629 } else {
1630 if (insn & (1 << 20))
1631 gen_op_iwmmxt_muluhw_M0_wRn(rd1);
1632 else
1633 gen_op_iwmmxt_mululw_M0_wRn(rd1);
1634 }
1635 gen_op_iwmmxt_movq_wRn_M0(wrd);
1636 gen_op_iwmmxt_set_mup();
1637 break;
1638 case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */
1639 wrd = (insn >> 12) & 0xf;
1640 rd0 = (insn >> 16) & 0xf;
1641 rd1 = (insn >> 0) & 0xf;
1642 gen_op_iwmmxt_movq_M0_wRn(rd0);
1643 if (insn & (1 << 21))
1644 gen_op_iwmmxt_macsw_M0_wRn(rd1);
1645 else
1646 gen_op_iwmmxt_macuw_M0_wRn(rd1);
1647 if (!(insn & (1 << 20))) {
1648 iwmmxt_load_reg(cpu_V1, wrd);
1649 tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1650 }
1651 gen_op_iwmmxt_movq_wRn_M0(wrd);
1652 gen_op_iwmmxt_set_mup();
1653 break;
1654 case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */
1655 wrd = (insn >> 12) & 0xf;
1656 rd0 = (insn >> 16) & 0xf;
1657 rd1 = (insn >> 0) & 0xf;
1658 gen_op_iwmmxt_movq_M0_wRn(rd0);
1659 switch ((insn >> 22) & 3) {
1660 case 0:
1661 gen_op_iwmmxt_cmpeqb_M0_wRn(rd1);
1662 break;
1663 case 1:
1664 gen_op_iwmmxt_cmpeqw_M0_wRn(rd1);
1665 break;
1666 case 2:
1667 gen_op_iwmmxt_cmpeql_M0_wRn(rd1);
1668 break;
1669 case 3:
1670 return 1;
1671 }
1672 gen_op_iwmmxt_movq_wRn_M0(wrd);
1673 gen_op_iwmmxt_set_mup();
1674 gen_op_iwmmxt_set_cup();
1675 break;
1676 case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */
1677 wrd = (insn >> 12) & 0xf;
1678 rd0 = (insn >> 16) & 0xf;
1679 rd1 = (insn >> 0) & 0xf;
1680 gen_op_iwmmxt_movq_M0_wRn(rd0);
1681 if (insn & (1 << 22)) {
1682 if (insn & (1 << 20))
1683 gen_op_iwmmxt_avgw1_M0_wRn(rd1);
1684 else
1685 gen_op_iwmmxt_avgw0_M0_wRn(rd1);
1686 } else {
1687 if (insn & (1 << 20))
1688 gen_op_iwmmxt_avgb1_M0_wRn(rd1);
1689 else
1690 gen_op_iwmmxt_avgb0_M0_wRn(rd1);
1691 }
1692 gen_op_iwmmxt_movq_wRn_M0(wrd);
1693 gen_op_iwmmxt_set_mup();
1694 gen_op_iwmmxt_set_cup();
1695 break;
1696 case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */
1697 wrd = (insn >> 12) & 0xf;
1698 rd0 = (insn >> 16) & 0xf;
1699 rd1 = (insn >> 0) & 0xf;
1700 gen_op_iwmmxt_movq_M0_wRn(rd0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02001701 tmp = iwmmxt_load_creg(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
1702 tcg_gen_andi_i32(tmp, tmp, 7);
1703 iwmmxt_load_reg(cpu_V1, rd1);
1704 gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
1705 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001706 gen_op_iwmmxt_movq_wRn_M0(wrd);
1707 gen_op_iwmmxt_set_mup();
1708 break;
1709 case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001710 if (((insn >> 6) & 3) == 3)
1711 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001712 rd = (insn >> 12) & 0xf;
1713 wrd = (insn >> 16) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001714 tmp = load_reg(s, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001715 gen_op_iwmmxt_movq_M0_wRn(wrd);
1716 switch ((insn >> 6) & 3) {
1717 case 0:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001718 tmp2 = tcg_const_i32(0xff);
1719 tmp3 = tcg_const_i32((insn & 7) << 3);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001720 break;
1721 case 1:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001722 tmp2 = tcg_const_i32(0xffff);
1723 tmp3 = tcg_const_i32((insn & 3) << 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001724 break;
1725 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001726 tmp2 = tcg_const_i32(0xffffffff);
1727 tmp3 = tcg_const_i32((insn & 1) << 5);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001728 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001729 default:
1730 TCGV_UNUSED(tmp2);
1731 TCGV_UNUSED(tmp3);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001732 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02001733 gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3);
1734 tcg_temp_free(tmp3);
1735 tcg_temp_free(tmp2);
1736 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001737 gen_op_iwmmxt_movq_wRn_M0(wrd);
1738 gen_op_iwmmxt_set_mup();
1739 break;
1740 case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */
1741 rd = (insn >> 12) & 0xf;
1742 wrd = (insn >> 16) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001743 if (rd == 15 || ((insn >> 22) & 3) == 3)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001744 return 1;
1745 gen_op_iwmmxt_movq_M0_wRn(wrd);
David 'Digit' Turner52858642011-06-03 13:41:05 +02001746 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001747 switch ((insn >> 22) & 3) {
1748 case 0:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001749 tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3);
1750 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1751 if (insn & 8) {
1752 tcg_gen_ext8s_i32(tmp, tmp);
1753 } else {
1754 tcg_gen_andi_i32(tmp, tmp, 0xff);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001755 }
1756 break;
1757 case 1:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001758 tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 3) << 4);
1759 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1760 if (insn & 8) {
1761 tcg_gen_ext16s_i32(tmp, tmp);
1762 } else {
1763 tcg_gen_andi_i32(tmp, tmp, 0xffff);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001764 }
1765 break;
1766 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001767 tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 1) << 5);
1768 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001769 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001770 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02001771 store_reg(s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001772 break;
1773 case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001774 if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001775 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001776 tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001777 switch ((insn >> 22) & 3) {
1778 case 0:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001779 tcg_gen_shri_i32(tmp, tmp, ((insn & 7) << 2) + 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001780 break;
1781 case 1:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001782 tcg_gen_shri_i32(tmp, tmp, ((insn & 3) << 3) + 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001783 break;
1784 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001785 tcg_gen_shri_i32(tmp, tmp, ((insn & 1) << 4) + 12);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001786 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001787 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02001788 tcg_gen_shli_i32(tmp, tmp, 28);
1789 gen_set_nzcv(tmp);
1790 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001791 break;
1792 case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001793 if (((insn >> 6) & 3) == 3)
1794 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001795 rd = (insn >> 12) & 0xf;
1796 wrd = (insn >> 16) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001797 tmp = load_reg(s, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001798 switch ((insn >> 6) & 3) {
1799 case 0:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001800 gen_helper_iwmmxt_bcstb(cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001801 break;
1802 case 1:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001803 gen_helper_iwmmxt_bcstw(cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001804 break;
1805 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001806 gen_helper_iwmmxt_bcstl(cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001807 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001808 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02001809 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001810 gen_op_iwmmxt_movq_wRn_M0(wrd);
1811 gen_op_iwmmxt_set_mup();
1812 break;
1813 case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001814 if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001815 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001816 tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
1817 tmp2 = tcg_temp_new_i32();
1818 tcg_gen_mov_i32(tmp2, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001819 switch ((insn >> 22) & 3) {
1820 case 0:
1821 for (i = 0; i < 7; i ++) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02001822 tcg_gen_shli_i32(tmp2, tmp2, 4);
1823 tcg_gen_and_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001824 }
1825 break;
1826 case 1:
1827 for (i = 0; i < 3; i ++) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02001828 tcg_gen_shli_i32(tmp2, tmp2, 8);
1829 tcg_gen_and_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001830 }
1831 break;
1832 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001833 tcg_gen_shli_i32(tmp2, tmp2, 16);
1834 tcg_gen_and_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001835 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001836 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02001837 gen_set_nzcv(tmp);
1838 tcg_temp_free_i32(tmp2);
1839 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001840 break;
1841 case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */
1842 wrd = (insn >> 12) & 0xf;
1843 rd0 = (insn >> 16) & 0xf;
1844 gen_op_iwmmxt_movq_M0_wRn(rd0);
1845 switch ((insn >> 22) & 3) {
1846 case 0:
1847 gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
1848 break;
1849 case 1:
1850 gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
1851 break;
1852 case 2:
1853 gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
1854 break;
1855 case 3:
1856 return 1;
1857 }
1858 gen_op_iwmmxt_movq_wRn_M0(wrd);
1859 gen_op_iwmmxt_set_mup();
1860 break;
1861 case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */
David 'Digit' Turner52858642011-06-03 13:41:05 +02001862 if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001863 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001864 tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
1865 tmp2 = tcg_temp_new_i32();
1866 tcg_gen_mov_i32(tmp2, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001867 switch ((insn >> 22) & 3) {
1868 case 0:
1869 for (i = 0; i < 7; i ++) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02001870 tcg_gen_shli_i32(tmp2, tmp2, 4);
1871 tcg_gen_or_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001872 }
1873 break;
1874 case 1:
1875 for (i = 0; i < 3; i ++) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02001876 tcg_gen_shli_i32(tmp2, tmp2, 8);
1877 tcg_gen_or_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001878 }
1879 break;
1880 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001881 tcg_gen_shli_i32(tmp2, tmp2, 16);
1882 tcg_gen_or_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001883 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001884 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02001885 gen_set_nzcv(tmp);
1886 tcg_temp_free_i32(tmp2);
1887 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001888 break;
1889 case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */
1890 rd = (insn >> 12) & 0xf;
1891 rd0 = (insn >> 16) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02001892 if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001893 return 1;
1894 gen_op_iwmmxt_movq_M0_wRn(rd0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02001895 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001896 switch ((insn >> 22) & 3) {
1897 case 0:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001898 gen_helper_iwmmxt_msbb(tmp, cpu_M0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001899 break;
1900 case 1:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001901 gen_helper_iwmmxt_msbw(tmp, cpu_M0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001902 break;
1903 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02001904 gen_helper_iwmmxt_msbl(tmp, cpu_M0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001905 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001906 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02001907 store_reg(s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001908 break;
1909 case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */
1910 case 0x906: case 0xb06: case 0xd06: case 0xf06:
1911 wrd = (insn >> 12) & 0xf;
1912 rd0 = (insn >> 16) & 0xf;
1913 rd1 = (insn >> 0) & 0xf;
1914 gen_op_iwmmxt_movq_M0_wRn(rd0);
1915 switch ((insn >> 22) & 3) {
1916 case 0:
1917 if (insn & (1 << 21))
1918 gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1);
1919 else
1920 gen_op_iwmmxt_cmpgtub_M0_wRn(rd1);
1921 break;
1922 case 1:
1923 if (insn & (1 << 21))
1924 gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1);
1925 else
1926 gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1);
1927 break;
1928 case 2:
1929 if (insn & (1 << 21))
1930 gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1);
1931 else
1932 gen_op_iwmmxt_cmpgtul_M0_wRn(rd1);
1933 break;
1934 case 3:
1935 return 1;
1936 }
1937 gen_op_iwmmxt_movq_wRn_M0(wrd);
1938 gen_op_iwmmxt_set_mup();
1939 gen_op_iwmmxt_set_cup();
1940 break;
1941 case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */
1942 case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
1943 wrd = (insn >> 12) & 0xf;
1944 rd0 = (insn >> 16) & 0xf;
1945 gen_op_iwmmxt_movq_M0_wRn(rd0);
1946 switch ((insn >> 22) & 3) {
1947 case 0:
1948 if (insn & (1 << 21))
1949 gen_op_iwmmxt_unpacklsb_M0();
1950 else
1951 gen_op_iwmmxt_unpacklub_M0();
1952 break;
1953 case 1:
1954 if (insn & (1 << 21))
1955 gen_op_iwmmxt_unpacklsw_M0();
1956 else
1957 gen_op_iwmmxt_unpackluw_M0();
1958 break;
1959 case 2:
1960 if (insn & (1 << 21))
1961 gen_op_iwmmxt_unpacklsl_M0();
1962 else
1963 gen_op_iwmmxt_unpacklul_M0();
1964 break;
1965 case 3:
1966 return 1;
1967 }
1968 gen_op_iwmmxt_movq_wRn_M0(wrd);
1969 gen_op_iwmmxt_set_mup();
1970 gen_op_iwmmxt_set_cup();
1971 break;
1972 case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */
1973 case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
1974 wrd = (insn >> 12) & 0xf;
1975 rd0 = (insn >> 16) & 0xf;
1976 gen_op_iwmmxt_movq_M0_wRn(rd0);
1977 switch ((insn >> 22) & 3) {
1978 case 0:
1979 if (insn & (1 << 21))
1980 gen_op_iwmmxt_unpackhsb_M0();
1981 else
1982 gen_op_iwmmxt_unpackhub_M0();
1983 break;
1984 case 1:
1985 if (insn & (1 << 21))
1986 gen_op_iwmmxt_unpackhsw_M0();
1987 else
1988 gen_op_iwmmxt_unpackhuw_M0();
1989 break;
1990 case 2:
1991 if (insn & (1 << 21))
1992 gen_op_iwmmxt_unpackhsl_M0();
1993 else
1994 gen_op_iwmmxt_unpackhul_M0();
1995 break;
1996 case 3:
1997 return 1;
1998 }
1999 gen_op_iwmmxt_movq_wRn_M0(wrd);
2000 gen_op_iwmmxt_set_mup();
2001 gen_op_iwmmxt_set_cup();
2002 break;
2003 case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */
2004 case 0x214: case 0x614: case 0xa14: case 0xe14:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002005 if (((insn >> 22) & 3) == 0)
2006 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002007 wrd = (insn >> 12) & 0xf;
2008 rd0 = (insn >> 16) & 0xf;
2009 gen_op_iwmmxt_movq_M0_wRn(rd0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002010 tmp = tcg_temp_new_i32();
2011 if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2012 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002013 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002014 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002015 switch ((insn >> 22) & 3) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002016 case 1:
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002017 gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002018 break;
2019 case 2:
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002020 gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002021 break;
2022 case 3:
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002023 gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002024 break;
2025 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02002026 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002027 gen_op_iwmmxt_movq_wRn_M0(wrd);
2028 gen_op_iwmmxt_set_mup();
2029 gen_op_iwmmxt_set_cup();
2030 break;
2031 case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */
2032 case 0x014: case 0x414: case 0x814: case 0xc14:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002033 if (((insn >> 22) & 3) == 0)
2034 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002035 wrd = (insn >> 12) & 0xf;
2036 rd0 = (insn >> 16) & 0xf;
2037 gen_op_iwmmxt_movq_M0_wRn(rd0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002038 tmp = tcg_temp_new_i32();
2039 if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2040 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002041 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002042 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002043 switch ((insn >> 22) & 3) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002044 case 1:
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002045 gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002046 break;
2047 case 2:
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002048 gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002049 break;
2050 case 3:
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002051 gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002052 break;
2053 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02002054 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002055 gen_op_iwmmxt_movq_wRn_M0(wrd);
2056 gen_op_iwmmxt_set_mup();
2057 gen_op_iwmmxt_set_cup();
2058 break;
2059 case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */
2060 case 0x114: case 0x514: case 0x914: case 0xd14:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002061 if (((insn >> 22) & 3) == 0)
2062 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002063 wrd = (insn >> 12) & 0xf;
2064 rd0 = (insn >> 16) & 0xf;
2065 gen_op_iwmmxt_movq_M0_wRn(rd0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002066 tmp = tcg_temp_new_i32();
2067 if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2068 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002069 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002070 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002071 switch ((insn >> 22) & 3) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002072 case 1:
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002073 gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002074 break;
2075 case 2:
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002076 gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002077 break;
2078 case 3:
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002079 gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002080 break;
2081 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02002082 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002083 gen_op_iwmmxt_movq_wRn_M0(wrd);
2084 gen_op_iwmmxt_set_mup();
2085 gen_op_iwmmxt_set_cup();
2086 break;
2087 case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */
2088 case 0x314: case 0x714: case 0xb14: case 0xf14:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002089 if (((insn >> 22) & 3) == 0)
2090 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002091 wrd = (insn >> 12) & 0xf;
2092 rd0 = (insn >> 16) & 0xf;
2093 gen_op_iwmmxt_movq_M0_wRn(rd0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002094 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002095 switch ((insn >> 22) & 3) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002096 case 1:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002097 if (gen_iwmmxt_shift(insn, 0xf, tmp)) {
2098 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002099 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002100 }
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002101 gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002102 break;
2103 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002104 if (gen_iwmmxt_shift(insn, 0x1f, tmp)) {
2105 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002106 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002107 }
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002108 gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002109 break;
2110 case 3:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002111 if (gen_iwmmxt_shift(insn, 0x3f, tmp)) {
2112 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002113 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002114 }
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002115 gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002116 break;
2117 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02002118 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002119 gen_op_iwmmxt_movq_wRn_M0(wrd);
2120 gen_op_iwmmxt_set_mup();
2121 gen_op_iwmmxt_set_cup();
2122 break;
2123 case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */
2124 case 0x916: case 0xb16: case 0xd16: case 0xf16:
2125 wrd = (insn >> 12) & 0xf;
2126 rd0 = (insn >> 16) & 0xf;
2127 rd1 = (insn >> 0) & 0xf;
2128 gen_op_iwmmxt_movq_M0_wRn(rd0);
2129 switch ((insn >> 22) & 3) {
2130 case 0:
2131 if (insn & (1 << 21))
2132 gen_op_iwmmxt_minsb_M0_wRn(rd1);
2133 else
2134 gen_op_iwmmxt_minub_M0_wRn(rd1);
2135 break;
2136 case 1:
2137 if (insn & (1 << 21))
2138 gen_op_iwmmxt_minsw_M0_wRn(rd1);
2139 else
2140 gen_op_iwmmxt_minuw_M0_wRn(rd1);
2141 break;
2142 case 2:
2143 if (insn & (1 << 21))
2144 gen_op_iwmmxt_minsl_M0_wRn(rd1);
2145 else
2146 gen_op_iwmmxt_minul_M0_wRn(rd1);
2147 break;
2148 case 3:
2149 return 1;
2150 }
2151 gen_op_iwmmxt_movq_wRn_M0(wrd);
2152 gen_op_iwmmxt_set_mup();
2153 break;
2154 case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */
2155 case 0x816: case 0xa16: case 0xc16: case 0xe16:
2156 wrd = (insn >> 12) & 0xf;
2157 rd0 = (insn >> 16) & 0xf;
2158 rd1 = (insn >> 0) & 0xf;
2159 gen_op_iwmmxt_movq_M0_wRn(rd0);
2160 switch ((insn >> 22) & 3) {
2161 case 0:
2162 if (insn & (1 << 21))
2163 gen_op_iwmmxt_maxsb_M0_wRn(rd1);
2164 else
2165 gen_op_iwmmxt_maxub_M0_wRn(rd1);
2166 break;
2167 case 1:
2168 if (insn & (1 << 21))
2169 gen_op_iwmmxt_maxsw_M0_wRn(rd1);
2170 else
2171 gen_op_iwmmxt_maxuw_M0_wRn(rd1);
2172 break;
2173 case 2:
2174 if (insn & (1 << 21))
2175 gen_op_iwmmxt_maxsl_M0_wRn(rd1);
2176 else
2177 gen_op_iwmmxt_maxul_M0_wRn(rd1);
2178 break;
2179 case 3:
2180 return 1;
2181 }
2182 gen_op_iwmmxt_movq_wRn_M0(wrd);
2183 gen_op_iwmmxt_set_mup();
2184 break;
2185 case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */
2186 case 0x402: case 0x502: case 0x602: case 0x702:
2187 wrd = (insn >> 12) & 0xf;
2188 rd0 = (insn >> 16) & 0xf;
2189 rd1 = (insn >> 0) & 0xf;
2190 gen_op_iwmmxt_movq_M0_wRn(rd0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002191 tmp = tcg_const_i32((insn >> 20) & 3);
2192 iwmmxt_load_reg(cpu_V1, rd1);
2193 gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
2194 tcg_temp_free(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002195 gen_op_iwmmxt_movq_wRn_M0(wrd);
2196 gen_op_iwmmxt_set_mup();
2197 break;
2198 case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */
2199 case 0x41a: case 0x51a: case 0x61a: case 0x71a:
2200 case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
2201 case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
2202 wrd = (insn >> 12) & 0xf;
2203 rd0 = (insn >> 16) & 0xf;
2204 rd1 = (insn >> 0) & 0xf;
2205 gen_op_iwmmxt_movq_M0_wRn(rd0);
2206 switch ((insn >> 20) & 0xf) {
2207 case 0x0:
2208 gen_op_iwmmxt_subnb_M0_wRn(rd1);
2209 break;
2210 case 0x1:
2211 gen_op_iwmmxt_subub_M0_wRn(rd1);
2212 break;
2213 case 0x3:
2214 gen_op_iwmmxt_subsb_M0_wRn(rd1);
2215 break;
2216 case 0x4:
2217 gen_op_iwmmxt_subnw_M0_wRn(rd1);
2218 break;
2219 case 0x5:
2220 gen_op_iwmmxt_subuw_M0_wRn(rd1);
2221 break;
2222 case 0x7:
2223 gen_op_iwmmxt_subsw_M0_wRn(rd1);
2224 break;
2225 case 0x8:
2226 gen_op_iwmmxt_subnl_M0_wRn(rd1);
2227 break;
2228 case 0x9:
2229 gen_op_iwmmxt_subul_M0_wRn(rd1);
2230 break;
2231 case 0xb:
2232 gen_op_iwmmxt_subsl_M0_wRn(rd1);
2233 break;
2234 default:
2235 return 1;
2236 }
2237 gen_op_iwmmxt_movq_wRn_M0(wrd);
2238 gen_op_iwmmxt_set_mup();
2239 gen_op_iwmmxt_set_cup();
2240 break;
2241 case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */
2242 case 0x41e: case 0x51e: case 0x61e: case 0x71e:
2243 case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
2244 case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
2245 wrd = (insn >> 12) & 0xf;
2246 rd0 = (insn >> 16) & 0xf;
2247 gen_op_iwmmxt_movq_M0_wRn(rd0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002248 tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f));
David 'Digit' Turnerc4e7d822014-04-03 00:13:57 +02002249 gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002250 tcg_temp_free(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002251 gen_op_iwmmxt_movq_wRn_M0(wrd);
2252 gen_op_iwmmxt_set_mup();
2253 gen_op_iwmmxt_set_cup();
2254 break;
2255 case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */
2256 case 0x418: case 0x518: case 0x618: case 0x718:
2257 case 0x818: case 0x918: case 0xa18: case 0xb18:
2258 case 0xc18: case 0xd18: case 0xe18: case 0xf18:
2259 wrd = (insn >> 12) & 0xf;
2260 rd0 = (insn >> 16) & 0xf;
2261 rd1 = (insn >> 0) & 0xf;
2262 gen_op_iwmmxt_movq_M0_wRn(rd0);
2263 switch ((insn >> 20) & 0xf) {
2264 case 0x0:
2265 gen_op_iwmmxt_addnb_M0_wRn(rd1);
2266 break;
2267 case 0x1:
2268 gen_op_iwmmxt_addub_M0_wRn(rd1);
2269 break;
2270 case 0x3:
2271 gen_op_iwmmxt_addsb_M0_wRn(rd1);
2272 break;
2273 case 0x4:
2274 gen_op_iwmmxt_addnw_M0_wRn(rd1);
2275 break;
2276 case 0x5:
2277 gen_op_iwmmxt_adduw_M0_wRn(rd1);
2278 break;
2279 case 0x7:
2280 gen_op_iwmmxt_addsw_M0_wRn(rd1);
2281 break;
2282 case 0x8:
2283 gen_op_iwmmxt_addnl_M0_wRn(rd1);
2284 break;
2285 case 0x9:
2286 gen_op_iwmmxt_addul_M0_wRn(rd1);
2287 break;
2288 case 0xb:
2289 gen_op_iwmmxt_addsl_M0_wRn(rd1);
2290 break;
2291 default:
2292 return 1;
2293 }
2294 gen_op_iwmmxt_movq_wRn_M0(wrd);
2295 gen_op_iwmmxt_set_mup();
2296 gen_op_iwmmxt_set_cup();
2297 break;
2298 case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */
2299 case 0x408: case 0x508: case 0x608: case 0x708:
2300 case 0x808: case 0x908: case 0xa08: case 0xb08:
2301 case 0xc08: case 0xd08: case 0xe08: case 0xf08:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002302 if (!(insn & (1 << 20)) || ((insn >> 22) & 3) == 0)
2303 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002304 wrd = (insn >> 12) & 0xf;
2305 rd0 = (insn >> 16) & 0xf;
2306 rd1 = (insn >> 0) & 0xf;
2307 gen_op_iwmmxt_movq_M0_wRn(rd0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002308 switch ((insn >> 22) & 3) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002309 case 1:
2310 if (insn & (1 << 21))
2311 gen_op_iwmmxt_packsw_M0_wRn(rd1);
2312 else
2313 gen_op_iwmmxt_packuw_M0_wRn(rd1);
2314 break;
2315 case 2:
2316 if (insn & (1 << 21))
2317 gen_op_iwmmxt_packsl_M0_wRn(rd1);
2318 else
2319 gen_op_iwmmxt_packul_M0_wRn(rd1);
2320 break;
2321 case 3:
2322 if (insn & (1 << 21))
2323 gen_op_iwmmxt_packsq_M0_wRn(rd1);
2324 else
2325 gen_op_iwmmxt_packuq_M0_wRn(rd1);
2326 break;
2327 }
2328 gen_op_iwmmxt_movq_wRn_M0(wrd);
2329 gen_op_iwmmxt_set_mup();
2330 gen_op_iwmmxt_set_cup();
2331 break;
2332 case 0x201: case 0x203: case 0x205: case 0x207:
2333 case 0x209: case 0x20b: case 0x20d: case 0x20f:
2334 case 0x211: case 0x213: case 0x215: case 0x217:
2335 case 0x219: case 0x21b: case 0x21d: case 0x21f:
2336 wrd = (insn >> 5) & 0xf;
2337 rd0 = (insn >> 12) & 0xf;
2338 rd1 = (insn >> 0) & 0xf;
2339 if (rd0 == 0xf || rd1 == 0xf)
2340 return 1;
2341 gen_op_iwmmxt_movq_M0_wRn(wrd);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002342 tmp = load_reg(s, rd0);
2343 tmp2 = load_reg(s, rd1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002344 switch ((insn >> 16) & 0xf) {
2345 case 0x0: /* TMIA */
David 'Digit' Turner52858642011-06-03 13:41:05 +02002346 gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002347 break;
2348 case 0x8: /* TMIAPH */
David 'Digit' Turner52858642011-06-03 13:41:05 +02002349 gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002350 break;
2351 case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002352 if (insn & (1 << 16))
David 'Digit' Turner52858642011-06-03 13:41:05 +02002353 tcg_gen_shri_i32(tmp, tmp, 16);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002354 if (insn & (1 << 17))
David 'Digit' Turner52858642011-06-03 13:41:05 +02002355 tcg_gen_shri_i32(tmp2, tmp2, 16);
2356 gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002357 break;
2358 default:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002359 tcg_temp_free_i32(tmp2);
2360 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002361 return 1;
2362 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02002363 tcg_temp_free_i32(tmp2);
2364 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002365 gen_op_iwmmxt_movq_wRn_M0(wrd);
2366 gen_op_iwmmxt_set_mup();
2367 break;
2368 default:
2369 return 1;
2370 }
2371
2372 return 0;
2373}
2374
David 'Digit' Turner52858642011-06-03 13:41:05 +02002375/* Disassemble an XScale DSP instruction. Returns nonzero if an error occurred
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002376 (ie. an undefined instruction). */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002377static int disas_dsp_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002378{
2379 int acc, rd0, rd1, rdhi, rdlo;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002380 TCGv tmp, tmp2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002381
2382 if ((insn & 0x0ff00f10) == 0x0e200010) {
2383 /* Multiply with Internal Accumulate Format */
2384 rd0 = (insn >> 12) & 0xf;
2385 rd1 = insn & 0xf;
2386 acc = (insn >> 5) & 7;
2387
2388 if (acc != 0)
2389 return 1;
2390
David 'Digit' Turner52858642011-06-03 13:41:05 +02002391 tmp = load_reg(s, rd0);
2392 tmp2 = load_reg(s, rd1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002393 switch ((insn >> 16) & 0xf) {
2394 case 0x0: /* MIA */
David 'Digit' Turner52858642011-06-03 13:41:05 +02002395 gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002396 break;
2397 case 0x8: /* MIAPH */
David 'Digit' Turner52858642011-06-03 13:41:05 +02002398 gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002399 break;
2400 case 0xc: /* MIABB */
2401 case 0xd: /* MIABT */
2402 case 0xe: /* MIATB */
2403 case 0xf: /* MIATT */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002404 if (insn & (1 << 16))
David 'Digit' Turner52858642011-06-03 13:41:05 +02002405 tcg_gen_shri_i32(tmp, tmp, 16);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002406 if (insn & (1 << 17))
David 'Digit' Turner52858642011-06-03 13:41:05 +02002407 tcg_gen_shri_i32(tmp2, tmp2, 16);
2408 gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002409 break;
2410 default:
2411 return 1;
2412 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02002413 tcg_temp_free_i32(tmp2);
2414 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002415
2416 gen_op_iwmmxt_movq_wRn_M0(acc);
2417 return 0;
2418 }
2419
2420 if ((insn & 0x0fe00ff8) == 0x0c400000) {
2421 /* Internal Accumulator Access Format */
2422 rdhi = (insn >> 16) & 0xf;
2423 rdlo = (insn >> 12) & 0xf;
2424 acc = insn & 7;
2425
2426 if (acc != 0)
2427 return 1;
2428
2429 if (insn & ARM_CP_RW_BIT) { /* MRA */
David 'Digit' Turner52858642011-06-03 13:41:05 +02002430 iwmmxt_load_reg(cpu_V0, acc);
2431 tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0);
2432 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
2433 tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0);
2434 tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002435 } else { /* MAR */
David 'Digit' Turner52858642011-06-03 13:41:05 +02002436 tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
2437 iwmmxt_store_reg(cpu_V0, acc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002438 }
2439 return 0;
2440 }
2441
2442 return 1;
2443}
2444
2445/* Disassemble system coprocessor instruction. Return nonzero if
2446 instruction is not defined. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002447static int disas_cp_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002448{
David 'Digit' Turner52858642011-06-03 13:41:05 +02002449 TCGv tmp, tmp2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002450 uint32_t rd = (insn >> 12) & 0xf;
2451 uint32_t cp = (insn >> 8) & 0xf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002452
2453 if (insn & ARM_CP_RW_BIT) {
2454 if (!env->cp[cp].cp_read)
2455 return 1;
2456 gen_set_pc_im(s->pc);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002457 tmp = tcg_temp_new_i32();
2458 tmp2 = tcg_const_i32(insn);
2459 gen_helper_get_cp(tmp, cpu_env, tmp2);
2460 tcg_temp_free(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002461 store_reg(s, rd, tmp);
2462 } else {
2463 if (!env->cp[cp].cp_write)
2464 return 1;
2465 gen_set_pc_im(s->pc);
2466 tmp = load_reg(s, rd);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002467 tmp2 = tcg_const_i32(insn);
2468 gen_helper_set_cp(cpu_env, tmp2, tmp);
2469 tcg_temp_free(tmp2);
2470 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002471 }
2472 return 0;
2473}
2474
David 'Digit' Turnerd9ac10a2014-03-19 11:01:43 +01002475static int cp15_user_ok(CPUARMState *env, uint32_t insn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002476{
2477 int cpn = (insn >> 16) & 0xf;
2478 int cpm = insn & 0xf;
2479 int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);
2480
David 'Digit' Turnerd9ac10a2014-03-19 11:01:43 +01002481 if (arm_feature(env, ARM_FEATURE_V7) && cpn == 9) {
2482 /* Performance monitor registers fall into three categories:
2483 * (a) always UNDEF in usermode
2484 * (b) UNDEF only if PMUSERENR.EN is 0
2485 * (c) always read OK and UNDEF on write (PMUSERENR only)
2486 */
2487 if ((cpm == 12 && (op < 6)) ||
2488 (cpm == 13 && (op < 3))) {
2489 return env->cp15.c9_pmuserenr;
2490 } else if (cpm == 14 && op == 0 && (insn & ARM_CP_RW_BIT)) {
2491 /* PMUSERENR, read only */
2492 return 1;
2493 }
2494 return 0;
2495 }
2496
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002497 if (cpn == 13 && cpm == 0) {
2498 /* TLS register. */
2499 if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT)))
2500 return 1;
2501 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002502 return 0;
2503}
2504
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002505static int cp15_tls_load_store(CPUARMState *env, DisasContext *s, uint32_t insn, uint32_t rd)
David 'Digit' Turner52858642011-06-03 13:41:05 +02002506{
2507 TCGv tmp;
2508 int cpn = (insn >> 16) & 0xf;
2509 int cpm = insn & 0xf;
2510 int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);
2511
2512 if (!arm_feature(env, ARM_FEATURE_V6K))
2513 return 0;
2514
2515 if (!(cpn == 13 && cpm == 0))
2516 return 0;
2517
2518 if (insn & ARM_CP_RW_BIT) {
2519 switch (op) {
2520 case 2:
2521 tmp = load_cpu_field(cp15.c13_tls1);
2522 break;
2523 case 3:
2524 tmp = load_cpu_field(cp15.c13_tls2);
2525 break;
2526 case 4:
2527 tmp = load_cpu_field(cp15.c13_tls3);
2528 break;
2529 default:
2530 return 0;
2531 }
2532 store_reg(s, rd, tmp);
2533
2534 } else {
2535 tmp = load_reg(s, rd);
2536 switch (op) {
2537 case 2:
2538 store_cpu_field(tmp, cp15.c13_tls1);
2539 break;
2540 case 3:
2541 store_cpu_field(tmp, cp15.c13_tls2);
2542 break;
2543 case 4:
2544 store_cpu_field(tmp, cp15.c13_tls3);
2545 break;
2546 default:
2547 tcg_temp_free_i32(tmp);
2548 return 0;
2549 }
2550 }
2551 return 1;
2552}
2553
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002554/* Disassemble system coprocessor (cp15) instruction. Return nonzero if
2555 instruction is not defined. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002556static int disas_cp15_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002557{
2558 uint32_t rd;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002559 TCGv tmp, tmp2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002560
2561 /* M profile cores use memory mapped registers instead of cp15. */
2562 if (arm_feature(env, ARM_FEATURE_M))
2563 return 1;
2564
2565 if ((insn & (1 << 25)) == 0) {
2566 if (insn & (1 << 20)) {
2567 /* mrrc */
2568 return 1;
2569 }
2570 /* mcrr. Used for block cache operations, so implement as no-op. */
2571 return 0;
2572 }
2573 if ((insn & (1 << 4)) == 0) {
2574 /* cdp */
2575 return 1;
2576 }
David 'Digit' Turner60148dc2014-03-19 11:42:58 +01002577 /* We special case a number of cp15 instructions which were used
2578 * for things which are real instructions in ARMv7. This allows
2579 * them to work in linux-user mode which doesn't provide functional
2580 * get_cp15/set_cp15 helpers, and is more efficient anyway.
David 'Digit' Turner52858642011-06-03 13:41:05 +02002581 */
David 'Digit' Turner60148dc2014-03-19 11:42:58 +01002582 switch ((insn & 0x0fff0fff)) {
2583 case 0x0e070f90:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002584 /* 0,c7,c0,4: Standard v6 WFI (also used in some pre-v6 cores).
2585 * In v7, this must NOP.
2586 */
David 'Digit' Turner60148dc2014-03-19 11:42:58 +01002587 if (IS_USER(s)) {
2588 return 1;
2589 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02002590 if (!arm_feature(env, ARM_FEATURE_V7)) {
2591 /* Wait for interrupt. */
2592 gen_set_pc_im(s->pc);
2593 s->is_jmp = DISAS_WFI;
2594 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002595 return 0;
David 'Digit' Turner60148dc2014-03-19 11:42:58 +01002596 case 0x0e070f58:
David 'Digit' Turner52858642011-06-03 13:41:05 +02002597 /* 0,c7,c8,2: Not all pre-v6 cores implemented this WFI,
2598 * so this is slightly over-broad.
2599 */
David 'Digit' Turner60148dc2014-03-19 11:42:58 +01002600 if (!IS_USER(s) && !arm_feature(env, ARM_FEATURE_V6)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02002601 /* Wait for interrupt. */
2602 gen_set_pc_im(s->pc);
2603 s->is_jmp = DISAS_WFI;
2604 return 0;
2605 }
David 'Digit' Turner60148dc2014-03-19 11:42:58 +01002606 /* Otherwise continue to handle via helper function.
David 'Digit' Turner52858642011-06-03 13:41:05 +02002607 * In particular, on v7 and some v6 cores this is one of
2608 * the VA-PA registers.
2609 */
David 'Digit' Turner60148dc2014-03-19 11:42:58 +01002610 break;
2611 case 0x0e070f3d:
2612 /* 0,c7,c13,1: prefetch-by-MVA in v6, NOP in v7 */
2613 if (arm_feature(env, ARM_FEATURE_V6)) {
2614 return IS_USER(s) ? 1 : 0;
2615 }
2616 break;
2617 case 0x0e070f95: /* 0,c7,c5,4 : ISB */
2618 case 0x0e070f9a: /* 0,c7,c10,4: DSB */
2619 case 0x0e070fba: /* 0,c7,c10,5: DMB */
2620 /* Barriers in both v6 and v7 */
2621 if (arm_feature(env, ARM_FEATURE_V6)) {
2622 return 0;
2623 }
2624 break;
2625 default:
2626 break;
2627 }
2628
2629 if (IS_USER(s) && !cp15_user_ok(env, insn)) {
2630 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002631 }
2632
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002633 rd = (insn >> 12) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002634
2635 if (cp15_tls_load_store(env, s, insn, rd))
2636 return 0;
2637
2638 tmp2 = tcg_const_i32(insn);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002639 if (insn & ARM_CP_RW_BIT) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02002640 tmp = tcg_temp_new_i32();
2641 gen_helper_get_cp15(tmp, cpu_env, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002642 /* If the destination register is r15 then sets condition codes. */
2643 if (rd != 15)
2644 store_reg(s, rd, tmp);
2645 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02002646 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002647 } else {
2648 tmp = load_reg(s, rd);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002649 gen_helper_set_cp15(cpu_env, tmp2, tmp);
2650 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002651 /* Normally we would always end the TB here, but Linux
2652 * arch/arm/mach-pxa/sleep.S expects two instructions following
2653 * an MMU enable to execute from cache. Imitate this behaviour. */
2654 if (!arm_feature(env, ARM_FEATURE_XSCALE) ||
2655 (insn & 0x0fff0fff) != 0x0e010f10)
2656 gen_lookup_tb(s);
2657 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02002658 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002659 return 0;
2660}
2661
2662#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n))
2663#define VFP_SREG(insn, bigbit, smallbit) \
2664 ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1))
2665#define VFP_DREG(reg, insn, bigbit, smallbit) do { \
2666 if (arm_feature(env, ARM_FEATURE_VFP3)) { \
2667 reg = (((insn) >> (bigbit)) & 0x0f) \
2668 | (((insn) >> ((smallbit) - 4)) & 0x10); \
2669 } else { \
2670 if (insn & (1 << (smallbit))) \
2671 return 1; \
2672 reg = ((insn) >> (bigbit)) & 0x0f; \
2673 }} while (0)
2674
2675#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22)
2676#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22)
2677#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7)
2678#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7)
2679#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5)
2680#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5)
2681
2682/* Move between integer and VFP cores. */
2683static TCGv gen_vfp_mrs(void)
2684{
David 'Digit' Turner52858642011-06-03 13:41:05 +02002685 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002686 tcg_gen_mov_i32(tmp, cpu_F0s);
2687 return tmp;
2688}
2689
2690static void gen_vfp_msr(TCGv tmp)
2691{
2692 tcg_gen_mov_i32(cpu_F0s, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002693 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002694}
2695
2696static void gen_neon_dup_u8(TCGv var, int shift)
2697{
David 'Digit' Turner52858642011-06-03 13:41:05 +02002698 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002699 if (shift)
2700 tcg_gen_shri_i32(var, var, shift);
2701 tcg_gen_ext8u_i32(var, var);
2702 tcg_gen_shli_i32(tmp, var, 8);
2703 tcg_gen_or_i32(var, var, tmp);
2704 tcg_gen_shli_i32(tmp, var, 16);
2705 tcg_gen_or_i32(var, var, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002706 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002707}
2708
2709static void gen_neon_dup_low16(TCGv var)
2710{
David 'Digit' Turner52858642011-06-03 13:41:05 +02002711 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002712 tcg_gen_ext16u_i32(var, var);
2713 tcg_gen_shli_i32(tmp, var, 16);
2714 tcg_gen_or_i32(var, var, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002715 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002716}
2717
2718static void gen_neon_dup_high16(TCGv var)
2719{
David 'Digit' Turner52858642011-06-03 13:41:05 +02002720 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002721 tcg_gen_andi_i32(var, var, 0xffff0000);
2722 tcg_gen_shri_i32(tmp, var, 16);
2723 tcg_gen_or_i32(var, var, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002724 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002725}
2726
David 'Digit' Turner52858642011-06-03 13:41:05 +02002727static TCGv gen_load_and_replicate(DisasContext *s, TCGv addr, int size)
2728{
2729 /* Load a single Neon element and replicate into a 32 bit TCG reg */
2730 TCGv tmp;
2731 switch (size) {
2732 case 0:
2733 tmp = gen_ld8u(addr, IS_USER(s));
2734 gen_neon_dup_u8(tmp, 0);
2735 break;
2736 case 1:
2737 tmp = gen_ld16u(addr, IS_USER(s));
2738 gen_neon_dup_low16(tmp);
2739 break;
2740 case 2:
2741 tmp = gen_ld32(addr, IS_USER(s));
2742 break;
2743 default: /* Avoid compiler warnings. */
2744 abort();
2745 }
2746 return tmp;
2747}
2748
2749/* Disassemble a VFP instruction. Returns nonzero if an error occurred
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002750 (ie. an undefined instruction). */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01002751static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002752{
2753 uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
2754 int dp, veclen;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002755 TCGv addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002756 TCGv tmp;
2757 TCGv tmp2;
2758
2759 if (!arm_feature(env, ARM_FEATURE_VFP))
2760 return 1;
2761
David 'Digit' Turner52858642011-06-03 13:41:05 +02002762 if (!s->vfp_enabled) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002763 /* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */
2764 if ((insn & 0x0fe00fff) != 0x0ee00a10)
2765 return 1;
2766 rn = (insn >> 16) & 0xf;
2767 if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
2768 && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
2769 return 1;
2770 }
2771 dp = ((insn & 0xf00) == 0xb00);
2772 switch ((insn >> 24) & 0xf) {
2773 case 0xe:
2774 if (insn & (1 << 4)) {
2775 /* single register transfer */
2776 rd = (insn >> 12) & 0xf;
2777 if (dp) {
2778 int size;
2779 int pass;
2780
2781 VFP_DREG_N(rn, insn);
2782 if (insn & 0xf)
2783 return 1;
2784 if (insn & 0x00c00060
2785 && !arm_feature(env, ARM_FEATURE_NEON))
2786 return 1;
2787
2788 pass = (insn >> 21) & 1;
2789 if (insn & (1 << 22)) {
2790 size = 0;
2791 offset = ((insn >> 5) & 3) * 8;
2792 } else if (insn & (1 << 5)) {
2793 size = 1;
2794 offset = (insn & (1 << 6)) ? 16 : 0;
2795 } else {
2796 size = 2;
2797 offset = 0;
2798 }
2799 if (insn & ARM_CP_RW_BIT) {
2800 /* vfp->arm */
2801 tmp = neon_load_reg(rn, pass);
2802 switch (size) {
2803 case 0:
2804 if (offset)
2805 tcg_gen_shri_i32(tmp, tmp, offset);
2806 if (insn & (1 << 23))
2807 gen_uxtb(tmp);
2808 else
2809 gen_sxtb(tmp);
2810 break;
2811 case 1:
2812 if (insn & (1 << 23)) {
2813 if (offset) {
2814 tcg_gen_shri_i32(tmp, tmp, 16);
2815 } else {
2816 gen_uxth(tmp);
2817 }
2818 } else {
2819 if (offset) {
2820 tcg_gen_sari_i32(tmp, tmp, 16);
2821 } else {
2822 gen_sxth(tmp);
2823 }
2824 }
2825 break;
2826 case 2:
2827 break;
2828 }
2829 store_reg(s, rd, tmp);
2830 } else {
2831 /* arm->vfp */
2832 tmp = load_reg(s, rd);
2833 if (insn & (1 << 23)) {
2834 /* VDUP */
2835 if (size == 0) {
2836 gen_neon_dup_u8(tmp, 0);
2837 } else if (size == 1) {
2838 gen_neon_dup_low16(tmp);
2839 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002840 for (n = 0; n <= pass * 2; n++) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02002841 tmp2 = tcg_temp_new_i32();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07002842 tcg_gen_mov_i32(tmp2, tmp);
2843 neon_store_reg(rn, n, tmp2);
2844 }
2845 neon_store_reg(rn, n, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002846 } else {
2847 /* VMOV */
2848 switch (size) {
2849 case 0:
2850 tmp2 = neon_load_reg(rn, pass);
2851 gen_bfi(tmp, tmp2, tmp, offset, 0xff);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002852 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002853 break;
2854 case 1:
2855 tmp2 = neon_load_reg(rn, pass);
2856 gen_bfi(tmp, tmp2, tmp, offset, 0xffff);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002857 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002858 break;
2859 case 2:
2860 break;
2861 }
2862 neon_store_reg(rn, pass, tmp);
2863 }
2864 }
2865 } else { /* !dp */
2866 if ((insn & 0x6f) != 0x00)
2867 return 1;
2868 rn = VFP_SREG_N(insn);
2869 if (insn & ARM_CP_RW_BIT) {
2870 /* vfp->arm */
2871 if (insn & (1 << 21)) {
2872 /* system register */
2873 rn >>= 1;
2874
2875 switch (rn) {
2876 case ARM_VFP_FPSID:
2877 /* VFP2 allows access to FSID from userspace.
2878 VFP3 restricts all id registers to privileged
2879 accesses. */
2880 if (IS_USER(s)
2881 && arm_feature(env, ARM_FEATURE_VFP3))
2882 return 1;
2883 tmp = load_cpu_field(vfp.xregs[rn]);
2884 break;
2885 case ARM_VFP_FPEXC:
2886 if (IS_USER(s))
2887 return 1;
2888 tmp = load_cpu_field(vfp.xregs[rn]);
2889 break;
2890 case ARM_VFP_FPINST:
2891 case ARM_VFP_FPINST2:
2892 /* Not present in VFP3. */
2893 if (IS_USER(s)
2894 || arm_feature(env, ARM_FEATURE_VFP3))
2895 return 1;
2896 tmp = load_cpu_field(vfp.xregs[rn]);
2897 break;
2898 case ARM_VFP_FPSCR:
2899 if (rd == 15) {
2900 tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
2901 tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
2902 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02002903 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002904 gen_helper_vfp_get_fpscr(tmp, cpu_env);
2905 }
2906 break;
2907 case ARM_VFP_MVFR0:
2908 case ARM_VFP_MVFR1:
2909 if (IS_USER(s)
2910 || !arm_feature(env, ARM_FEATURE_VFP3))
2911 return 1;
2912 tmp = load_cpu_field(vfp.xregs[rn]);
2913 break;
2914 default:
2915 return 1;
2916 }
2917 } else {
2918 gen_mov_F0_vreg(0, rn);
2919 tmp = gen_vfp_mrs();
2920 }
2921 if (rd == 15) {
2922 /* Set the 4 flag bits in the CPSR. */
2923 gen_set_nzcv(tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002924 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002925 } else {
2926 store_reg(s, rd, tmp);
2927 }
2928 } else {
2929 /* arm->vfp */
2930 tmp = load_reg(s, rd);
2931 if (insn & (1 << 21)) {
2932 rn >>= 1;
2933 /* system register */
2934 switch (rn) {
2935 case ARM_VFP_FPSID:
2936 case ARM_VFP_MVFR0:
2937 case ARM_VFP_MVFR1:
2938 /* Writes are ignored. */
2939 break;
2940 case ARM_VFP_FPSCR:
2941 gen_helper_vfp_set_fpscr(cpu_env, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02002942 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002943 gen_lookup_tb(s);
2944 break;
2945 case ARM_VFP_FPEXC:
2946 if (IS_USER(s))
2947 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02002948 /* TODO: VFP subarchitecture support.
2949 * For now, keep the EN bit only */
2950 tcg_gen_andi_i32(tmp, tmp, 1 << 30);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002951 store_cpu_field(tmp, vfp.xregs[rn]);
2952 gen_lookup_tb(s);
2953 break;
2954 case ARM_VFP_FPINST:
2955 case ARM_VFP_FPINST2:
2956 store_cpu_field(tmp, vfp.xregs[rn]);
2957 break;
2958 default:
2959 return 1;
2960 }
2961 } else {
2962 gen_vfp_msr(tmp);
2963 gen_mov_vreg_F0(0, rn);
2964 }
2965 }
2966 }
2967 } else {
2968 /* data processing */
2969 /* The opcode is in bits 23, 21, 20 and 6. */
2970 op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
2971 if (dp) {
2972 if (op == 15) {
2973 /* rn is opcode */
2974 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
2975 } else {
2976 /* rn is register number */
2977 VFP_DREG_N(rn, insn);
2978 }
2979
David 'Digit' Turner52858642011-06-03 13:41:05 +02002980 if (op == 15 && (rn == 15 || ((rn & 0x1c) == 0x18))) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002981 /* Integer or single precision destination. */
2982 rd = VFP_SREG_D(insn);
2983 } else {
2984 VFP_DREG_D(rd, insn);
2985 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02002986 if (op == 15 &&
2987 (((rn & 0x1c) == 0x10) || ((rn & 0x14) == 0x14))) {
2988 /* VCVT from int is always from S reg regardless of dp bit.
2989 * VCVT with immediate frac_bits has same format as SREG_M
2990 */
2991 rm = VFP_SREG_M(insn);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08002992 } else {
2993 VFP_DREG_M(rm, insn);
2994 }
2995 } else {
2996 rn = VFP_SREG_N(insn);
2997 if (op == 15 && rn == 15) {
2998 /* Double precision destination. */
2999 VFP_DREG_D(rd, insn);
3000 } else {
3001 rd = VFP_SREG_D(insn);
3002 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003003 /* NB that we implicitly rely on the encoding for the frac_bits
3004 * in VCVT of fixed to float being the same as that of an SREG_M
3005 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003006 rm = VFP_SREG_M(insn);
3007 }
3008
David 'Digit' Turner52858642011-06-03 13:41:05 +02003009 veclen = s->vec_len;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003010 if (op == 15 && rn > 3)
3011 veclen = 0;
3012
3013 /* Shut up compiler warnings. */
3014 delta_m = 0;
3015 delta_d = 0;
3016 bank_mask = 0;
3017
3018 if (veclen > 0) {
3019 if (dp)
3020 bank_mask = 0xc;
3021 else
3022 bank_mask = 0x18;
3023
3024 /* Figure out what type of vector operation this is. */
3025 if ((rd & bank_mask) == 0) {
3026 /* scalar */
3027 veclen = 0;
3028 } else {
3029 if (dp)
David 'Digit' Turner52858642011-06-03 13:41:05 +02003030 delta_d = (s->vec_stride >> 1) + 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003031 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02003032 delta_d = s->vec_stride + 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003033
3034 if ((rm & bank_mask) == 0) {
3035 /* mixed scalar/vector */
3036 delta_m = 0;
3037 } else {
3038 /* vector */
3039 delta_m = delta_d;
3040 }
3041 }
3042 }
3043
3044 /* Load the initial operands. */
3045 if (op == 15) {
3046 switch (rn) {
3047 case 16:
3048 case 17:
3049 /* Integer source */
3050 gen_mov_F0_vreg(0, rm);
3051 break;
3052 case 8:
3053 case 9:
3054 /* Compare */
3055 gen_mov_F0_vreg(dp, rd);
3056 gen_mov_F1_vreg(dp, rm);
3057 break;
3058 case 10:
3059 case 11:
3060 /* Compare with zero */
3061 gen_mov_F0_vreg(dp, rd);
3062 gen_vfp_F1_ld0(dp);
3063 break;
3064 case 20:
3065 case 21:
3066 case 22:
3067 case 23:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003068 case 28:
3069 case 29:
3070 case 30:
3071 case 31:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003072 /* Source and destination the same. */
3073 gen_mov_F0_vreg(dp, rd);
3074 break;
David 'Digit' Turnercf2ea592014-03-19 11:53:41 +01003075 case 4:
3076 case 5:
3077 case 6:
3078 case 7:
3079 /* VCVTB, VCVTT: only present with the halfprec extension,
3080 * UNPREDICTABLE if bit 8 is set (we choose to UNDEF)
3081 */
3082 if (dp || !arm_feature(env, ARM_FEATURE_VFP_FP16)) {
3083 return 1;
3084 }
3085 /* Otherwise fall through */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003086 default:
3087 /* One source operand. */
3088 gen_mov_F0_vreg(dp, rm);
3089 break;
3090 }
3091 } else {
3092 /* Two source operands. */
3093 gen_mov_F0_vreg(dp, rn);
3094 gen_mov_F1_vreg(dp, rm);
3095 }
3096
3097 for (;;) {
3098 /* Perform the calculation. */
3099 switch (op) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02003100 case 0: /* VMLA: fd + (fn * fm) */
3101 /* Note that order of inputs to the add matters for NaNs */
3102 gen_vfp_F1_mul(dp);
3103 gen_mov_F0_vreg(dp, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003104 gen_vfp_add(dp);
3105 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003106 case 1: /* VMLS: fd + -(fn * fm) */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003107 gen_vfp_mul(dp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003108 gen_vfp_F1_neg(dp);
3109 gen_mov_F0_vreg(dp, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003110 gen_vfp_add(dp);
3111 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003112 case 2: /* VNMLS: -fd + (fn * fm) */
3113 /* Note that it isn't valid to replace (-A + B) with (B - A)
3114 * or similar plausible looking simplifications
3115 * because this will give wrong results for NaNs.
3116 */
3117 gen_vfp_F1_mul(dp);
3118 gen_mov_F0_vreg(dp, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003119 gen_vfp_neg(dp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003120 gen_vfp_add(dp);
3121 break;
3122 case 3: /* VNMLA: -fd + -(fn * fm) */
3123 gen_vfp_mul(dp);
3124 gen_vfp_F1_neg(dp);
3125 gen_mov_F0_vreg(dp, rd);
3126 gen_vfp_neg(dp);
3127 gen_vfp_add(dp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003128 break;
3129 case 4: /* mul: fn * fm */
3130 gen_vfp_mul(dp);
3131 break;
3132 case 5: /* nmul: -(fn * fm) */
3133 gen_vfp_mul(dp);
3134 gen_vfp_neg(dp);
3135 break;
3136 case 6: /* add: fn + fm */
3137 gen_vfp_add(dp);
3138 break;
3139 case 7: /* sub: fn - fm */
3140 gen_vfp_sub(dp);
3141 break;
3142 case 8: /* div: fn / fm */
3143 gen_vfp_div(dp);
3144 break;
3145 case 14: /* fconst */
3146 if (!arm_feature(env, ARM_FEATURE_VFP3))
3147 return 1;
3148
3149 n = (insn << 12) & 0x80000000;
3150 i = ((insn >> 12) & 0x70) | (insn & 0xf);
3151 if (dp) {
3152 if (i & 0x40)
3153 i |= 0x3f80;
3154 else
3155 i |= 0x4000;
3156 n |= i << 16;
3157 tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
3158 } else {
3159 if (i & 0x40)
3160 i |= 0x780;
3161 else
3162 i |= 0x800;
3163 n |= i << 19;
3164 tcg_gen_movi_i32(cpu_F0s, n);
3165 }
3166 break;
3167 case 15: /* extension space */
3168 switch (rn) {
3169 case 0: /* cpy */
3170 /* no-op */
3171 break;
3172 case 1: /* abs */
3173 gen_vfp_abs(dp);
3174 break;
3175 case 2: /* neg */
3176 gen_vfp_neg(dp);
3177 break;
3178 case 3: /* sqrt */
3179 gen_vfp_sqrt(dp);
3180 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003181 case 4: /* vcvtb.f32.f16 */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003182 tmp = gen_vfp_mrs();
3183 tcg_gen_ext16u_i32(tmp, tmp);
3184 gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
3185 tcg_temp_free_i32(tmp);
3186 break;
3187 case 5: /* vcvtt.f32.f16 */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003188 tmp = gen_vfp_mrs();
3189 tcg_gen_shri_i32(tmp, tmp, 16);
3190 gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
3191 tcg_temp_free_i32(tmp);
3192 break;
3193 case 6: /* vcvtb.f16.f32 */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003194 tmp = tcg_temp_new_i32();
3195 gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
3196 gen_mov_F0_vreg(0, rd);
3197 tmp2 = gen_vfp_mrs();
3198 tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
3199 tcg_gen_or_i32(tmp, tmp, tmp2);
3200 tcg_temp_free_i32(tmp2);
3201 gen_vfp_msr(tmp);
3202 break;
3203 case 7: /* vcvtt.f16.f32 */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003204 tmp = tcg_temp_new_i32();
3205 gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
3206 tcg_gen_shli_i32(tmp, tmp, 16);
3207 gen_mov_F0_vreg(0, rd);
3208 tmp2 = gen_vfp_mrs();
3209 tcg_gen_ext16u_i32(tmp2, tmp2);
3210 tcg_gen_or_i32(tmp, tmp, tmp2);
3211 tcg_temp_free_i32(tmp2);
3212 gen_vfp_msr(tmp);
3213 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003214 case 8: /* cmp */
3215 gen_vfp_cmp(dp);
3216 break;
3217 case 9: /* cmpe */
3218 gen_vfp_cmpe(dp);
3219 break;
3220 case 10: /* cmpz */
3221 gen_vfp_cmp(dp);
3222 break;
3223 case 11: /* cmpez */
3224 gen_vfp_F1_ld0(dp);
3225 gen_vfp_cmpe(dp);
3226 break;
3227 case 15: /* single<->double conversion */
3228 if (dp)
3229 gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
3230 else
3231 gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
3232 break;
3233 case 16: /* fuito */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003234 gen_vfp_uito(dp, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003235 break;
3236 case 17: /* fsito */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003237 gen_vfp_sito(dp, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003238 break;
3239 case 20: /* fshto */
3240 if (!arm_feature(env, ARM_FEATURE_VFP3))
3241 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003242 gen_vfp_shto(dp, 16 - rm, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003243 break;
3244 case 21: /* fslto */
3245 if (!arm_feature(env, ARM_FEATURE_VFP3))
3246 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003247 gen_vfp_slto(dp, 32 - rm, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003248 break;
3249 case 22: /* fuhto */
3250 if (!arm_feature(env, ARM_FEATURE_VFP3))
3251 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003252 gen_vfp_uhto(dp, 16 - rm, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003253 break;
3254 case 23: /* fulto */
3255 if (!arm_feature(env, ARM_FEATURE_VFP3))
3256 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003257 gen_vfp_ulto(dp, 32 - rm, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003258 break;
3259 case 24: /* ftoui */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003260 gen_vfp_toui(dp, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003261 break;
3262 case 25: /* ftouiz */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003263 gen_vfp_touiz(dp, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003264 break;
3265 case 26: /* ftosi */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003266 gen_vfp_tosi(dp, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003267 break;
3268 case 27: /* ftosiz */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003269 gen_vfp_tosiz(dp, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003270 break;
3271 case 28: /* ftosh */
3272 if (!arm_feature(env, ARM_FEATURE_VFP3))
3273 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003274 gen_vfp_tosh(dp, 16 - rm, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003275 break;
3276 case 29: /* ftosl */
3277 if (!arm_feature(env, ARM_FEATURE_VFP3))
3278 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003279 gen_vfp_tosl(dp, 32 - rm, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003280 break;
3281 case 30: /* ftouh */
3282 if (!arm_feature(env, ARM_FEATURE_VFP3))
3283 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003284 gen_vfp_touh(dp, 16 - rm, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003285 break;
3286 case 31: /* ftoul */
3287 if (!arm_feature(env, ARM_FEATURE_VFP3))
3288 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003289 gen_vfp_toul(dp, 32 - rm, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003290 break;
3291 default: /* undefined */
3292 printf ("rn:%d\n", rn);
3293 return 1;
3294 }
3295 break;
3296 default: /* undefined */
3297 printf ("op:%d\n", op);
3298 return 1;
3299 }
3300
3301 /* Write back the result. */
3302 if (op == 15 && (rn >= 8 && rn <= 11))
3303 ; /* Comparison, do nothing. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003304 else if (op == 15 && dp && ((rn & 0x1c) == 0x18))
3305 /* VCVT double to int: always integer result. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003306 gen_mov_vreg_F0(0, rd);
3307 else if (op == 15 && rn == 15)
3308 /* conversion */
3309 gen_mov_vreg_F0(!dp, rd);
3310 else
3311 gen_mov_vreg_F0(dp, rd);
3312
3313 /* break out of the loop if we have finished */
3314 if (veclen == 0)
3315 break;
3316
3317 if (op == 15 && delta_m == 0) {
3318 /* single source one-many */
3319 while (veclen--) {
3320 rd = ((rd + delta_d) & (bank_mask - 1))
3321 | (rd & bank_mask);
3322 gen_mov_vreg_F0(dp, rd);
3323 }
3324 break;
3325 }
3326 /* Setup the next operands. */
3327 veclen--;
3328 rd = ((rd + delta_d) & (bank_mask - 1))
3329 | (rd & bank_mask);
3330
3331 if (op == 15) {
3332 /* One source operand. */
3333 rm = ((rm + delta_m) & (bank_mask - 1))
3334 | (rm & bank_mask);
3335 gen_mov_F0_vreg(dp, rm);
3336 } else {
3337 /* Two source operands. */
3338 rn = ((rn + delta_d) & (bank_mask - 1))
3339 | (rn & bank_mask);
3340 gen_mov_F0_vreg(dp, rn);
3341 if (delta_m) {
3342 rm = ((rm + delta_m) & (bank_mask - 1))
3343 | (rm & bank_mask);
3344 gen_mov_F1_vreg(dp, rm);
3345 }
3346 }
3347 }
3348 }
3349 break;
3350 case 0xc:
3351 case 0xd:
David 'Digit' Turner52858642011-06-03 13:41:05 +02003352 if ((insn & 0x03e00000) == 0x00400000) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003353 /* two-register transfer */
3354 rn = (insn >> 16) & 0xf;
3355 rd = (insn >> 12) & 0xf;
3356 if (dp) {
3357 VFP_DREG_M(rm, insn);
3358 } else {
3359 rm = VFP_SREG_M(insn);
3360 }
3361
3362 if (insn & ARM_CP_RW_BIT) {
3363 /* vfp->arm */
3364 if (dp) {
3365 gen_mov_F0_vreg(0, rm * 2);
3366 tmp = gen_vfp_mrs();
3367 store_reg(s, rd, tmp);
3368 gen_mov_F0_vreg(0, rm * 2 + 1);
3369 tmp = gen_vfp_mrs();
3370 store_reg(s, rn, tmp);
3371 } else {
3372 gen_mov_F0_vreg(0, rm);
3373 tmp = gen_vfp_mrs();
David 'Digit' Turner52858642011-06-03 13:41:05 +02003374 store_reg(s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003375 gen_mov_F0_vreg(0, rm + 1);
3376 tmp = gen_vfp_mrs();
David 'Digit' Turner52858642011-06-03 13:41:05 +02003377 store_reg(s, rn, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003378 }
3379 } else {
3380 /* arm->vfp */
3381 if (dp) {
3382 tmp = load_reg(s, rd);
3383 gen_vfp_msr(tmp);
3384 gen_mov_vreg_F0(0, rm * 2);
3385 tmp = load_reg(s, rn);
3386 gen_vfp_msr(tmp);
3387 gen_mov_vreg_F0(0, rm * 2 + 1);
3388 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02003389 tmp = load_reg(s, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003390 gen_vfp_msr(tmp);
3391 gen_mov_vreg_F0(0, rm);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003392 tmp = load_reg(s, rn);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003393 gen_vfp_msr(tmp);
3394 gen_mov_vreg_F0(0, rm + 1);
3395 }
3396 }
3397 } else {
3398 /* Load/store */
3399 rn = (insn >> 16) & 0xf;
3400 if (dp)
3401 VFP_DREG_D(rd, insn);
3402 else
3403 rd = VFP_SREG_D(insn);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003404 if ((insn & 0x01200000) == 0x01000000) {
3405 /* Single load/store */
3406 offset = (insn & 0xff) << 2;
3407 if ((insn & (1 << 23)) == 0)
3408 offset = -offset;
David 'Digit' Turner97c98d32014-03-19 11:46:32 +01003409 if (s->thumb && rn == 15) {
3410 /* This is actually UNPREDICTABLE */
3411 addr = tcg_temp_new_i32();
3412 tcg_gen_movi_i32(addr, s->pc & ~2);
3413 } else {
3414 addr = load_reg(s, rn);
3415 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003416 tcg_gen_addi_i32(addr, addr, offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003417 if (insn & (1 << 20)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02003418 gen_vfp_ld(s, dp, addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003419 gen_mov_vreg_F0(dp, rd);
3420 } else {
3421 gen_mov_F0_vreg(dp, rd);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003422 gen_vfp_st(s, dp, addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003423 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003424 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003425 } else {
3426 /* load/store multiple */
David 'Digit' Turner97c98d32014-03-19 11:46:32 +01003427 int w = insn & (1 << 21);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003428 if (dp)
3429 n = (insn >> 1) & 0x7f;
3430 else
3431 n = insn & 0xff;
3432
David 'Digit' Turner97c98d32014-03-19 11:46:32 +01003433 if (w && !(((insn >> 23) ^ (insn >> 24)) & 1)) {
3434 /* P == U , W == 1 => UNDEF */
3435 return 1;
3436 }
3437 if (n == 0 || (rd + n) > 32 || (dp && n > 16)) {
3438 /* UNPREDICTABLE cases for bad immediates: we choose to
3439 * UNDEF to avoid generating huge numbers of TCG ops
3440 */
3441 return 1;
3442 }
3443 if (rn == 15 && w) {
3444 /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
3445 return 1;
3446 }
3447
3448 if (s->thumb && rn == 15) {
3449 /* This is actually UNPREDICTABLE */
3450 addr = tcg_temp_new_i32();
3451 tcg_gen_movi_i32(addr, s->pc & ~2);
3452 } else {
3453 addr = load_reg(s, rn);
3454 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003455 if (insn & (1 << 24)) /* pre-decrement */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003456 tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003457
3458 if (dp)
3459 offset = 8;
3460 else
3461 offset = 4;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003462 tmp = tcg_const_i32(offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003463 for (i = 0; i < n; i++) {
3464 if (insn & ARM_CP_RW_BIT) {
3465 /* load */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003466 gen_vfp_ld(s, dp, addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003467 gen_mov_vreg_F0(dp, rd + i);
3468 } else {
3469 /* store */
3470 gen_mov_F0_vreg(dp, rd + i);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003471 gen_vfp_st(s, dp, addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003472 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003473 tcg_gen_add_i32(addr, addr, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003474 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003475 tcg_temp_free_i32(tmp);
David 'Digit' Turner97c98d32014-03-19 11:46:32 +01003476 if (w) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003477 /* writeback */
3478 if (insn & (1 << 24))
3479 offset = -offset * n;
3480 else if (dp && (insn & 1))
3481 offset = 4;
3482 else
3483 offset = 0;
3484
3485 if (offset != 0)
David 'Digit' Turner52858642011-06-03 13:41:05 +02003486 tcg_gen_addi_i32(addr, addr, offset);
3487 store_reg(s, rn, addr);
3488 } else {
3489 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003490 }
3491 }
3492 }
3493 break;
3494 default:
3495 /* Should never happen. */
3496 return 1;
3497 }
3498 return 0;
3499}
3500
3501static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
3502{
3503 TranslationBlock *tb;
3504
3505 tb = s->tb;
3506 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
3507 tcg_gen_goto_tb(n);
3508 gen_set_pc_im(dest);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003509 tcg_gen_exit_tb((tcg_target_long)tb + n);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003510 } else {
3511 gen_set_pc_im(dest);
3512 tcg_gen_exit_tb(0);
3513 }
3514}
3515
3516static inline void gen_jmp (DisasContext *s, uint32_t dest)
3517{
3518 if (unlikely(s->singlestep_enabled)) {
3519 /* An indirect jump so that we still trigger the debug exception. */
3520 if (s->thumb)
3521 dest |= 1;
3522 gen_bx_im(s, dest);
3523 } else {
3524 gen_goto_tb(s, 0, dest);
3525 s->is_jmp = DISAS_TB_JUMP;
3526 }
3527}
3528
3529static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y)
3530{
3531 if (x)
3532 tcg_gen_sari_i32(t0, t0, 16);
3533 else
3534 gen_sxth(t0);
3535 if (y)
3536 tcg_gen_sari_i32(t1, t1, 16);
3537 else
3538 gen_sxth(t1);
3539 tcg_gen_mul_i32(t0, t0, t1);
3540}
3541
3542/* Return the mask of PSR bits set by a MSR instruction. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01003543static uint32_t msr_mask(CPUARMState *env, DisasContext *s, int flags, int spsr) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003544 uint32_t mask;
3545
3546 mask = 0;
3547 if (flags & (1 << 0))
3548 mask |= 0xff;
3549 if (flags & (1 << 1))
3550 mask |= 0xff00;
3551 if (flags & (1 << 2))
3552 mask |= 0xff0000;
3553 if (flags & (1 << 3))
3554 mask |= 0xff000000;
3555
3556 /* Mask out undefined bits. */
3557 mask &= ~CPSR_RESERVED;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003558 if (!arm_feature(env, ARM_FEATURE_V4T))
3559 mask &= ~CPSR_T;
3560 if (!arm_feature(env, ARM_FEATURE_V5))
3561 mask &= ~CPSR_Q; /* V5TE in reality*/
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003562 if (!arm_feature(env, ARM_FEATURE_V6))
3563 mask &= ~(CPSR_E | CPSR_GE);
3564 if (!arm_feature(env, ARM_FEATURE_THUMB2))
3565 mask &= ~CPSR_IT;
3566 /* Mask out execution state bits. */
3567 if (!spsr)
3568 mask &= ~CPSR_EXEC;
3569 /* Mask out privileged bits. */
3570 if (IS_USER(s))
3571 mask &= CPSR_USER;
3572 return mask;
3573}
3574
David 'Digit' Turner52858642011-06-03 13:41:05 +02003575/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
3576static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv t0)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003577{
3578 TCGv tmp;
3579 if (spsr) {
3580 /* ??? This is also undefined in system mode. */
3581 if (IS_USER(s))
3582 return 1;
3583
3584 tmp = load_cpu_field(spsr);
3585 tcg_gen_andi_i32(tmp, tmp, ~mask);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003586 tcg_gen_andi_i32(t0, t0, mask);
3587 tcg_gen_or_i32(tmp, tmp, t0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003588 store_cpu_field(tmp, spsr);
3589 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02003590 gen_set_cpsr(t0, mask);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003591 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003592 tcg_temp_free_i32(t0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003593 gen_lookup_tb(s);
3594 return 0;
3595}
3596
David 'Digit' Turner52858642011-06-03 13:41:05 +02003597/* Returns nonzero if access to the PSR is not permitted. */
3598static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val)
3599{
3600 TCGv tmp;
3601 tmp = tcg_temp_new_i32();
3602 tcg_gen_movi_i32(tmp, val);
3603 return gen_set_psr(s, mask, spsr, tmp);
3604}
3605
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003606/* Generate an old-style exception return. Marks pc as dead. */
3607static void gen_exception_return(DisasContext *s, TCGv pc)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003608{
3609 TCGv tmp;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07003610 store_reg(s, 15, pc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003611 tmp = load_cpu_field(spsr);
3612 gen_set_cpsr(tmp, 0xffffffff);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003613 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003614 s->is_jmp = DISAS_UPDATE;
3615}
3616
3617/* Generate a v6 exception return. Marks both values as dead. */
3618static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr)
3619{
3620 gen_set_cpsr(cpsr, 0xffffffff);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003621 tcg_temp_free_i32(cpsr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003622 store_reg(s, 15, pc);
3623 s->is_jmp = DISAS_UPDATE;
3624}
3625
3626static inline void
3627gen_set_condexec (DisasContext *s)
3628{
Vladimir Chtchetkinea1204592010-04-02 11:03:19 -07003629 if (s->condexec_mask) {
3630 uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003631 TCGv tmp = tcg_temp_new_i32();
Vladimir Chtchetkinea1204592010-04-02 11:03:19 -07003632 tcg_gen_movi_i32(tmp, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003633 store_cpu_field(tmp, condexec_bits);
Vladimir Chtchetkinea1204592010-04-02 11:03:19 -07003634 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003635}
3636
3637static void gen_exception_insn(DisasContext *s, int offset, int excp)
3638{
3639 gen_set_condexec(s);
3640 gen_set_pc_im(s->pc - offset);
3641 gen_exception(excp);
3642 s->is_jmp = DISAS_JUMP;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003643}
3644
3645static void gen_nop_hint(DisasContext *s, int val)
3646{
3647 switch (val) {
3648 case 3: /* wfi */
3649 gen_set_pc_im(s->pc);
3650 s->is_jmp = DISAS_WFI;
3651 break;
3652 case 2: /* wfe */
3653 case 4: /* sev */
3654 /* TODO: Implement SEV and WFE. May help SMP performance. */
3655 default: /* nop */
3656 break;
3657 }
3658}
3659
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003660#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
3661
David 'Digit' Turner52858642011-06-03 13:41:05 +02003662static inline void gen_neon_add(int size, TCGv t0, TCGv t1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003663{
3664 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02003665 case 0: gen_helper_neon_add_u8(t0, t0, t1); break;
3666 case 1: gen_helper_neon_add_u16(t0, t0, t1); break;
3667 case 2: tcg_gen_add_i32(t0, t0, t1); break;
3668 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003669 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003670}
3671
David 'Digit' Turner52858642011-06-03 13:41:05 +02003672static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003673{
3674 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02003675 case 0: gen_helper_neon_sub_u8(t0, t1, t0); break;
3676 case 1: gen_helper_neon_sub_u16(t0, t1, t0); break;
3677 case 2: tcg_gen_sub_i32(t0, t1, t0); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003678 default: return;
3679 }
3680}
3681
3682/* 32-bit pairwise ops end up the same as the elementwise versions. */
3683#define gen_helper_neon_pmax_s32 gen_helper_neon_max_s32
3684#define gen_helper_neon_pmax_u32 gen_helper_neon_max_u32
3685#define gen_helper_neon_pmin_s32 gen_helper_neon_min_s32
3686#define gen_helper_neon_pmin_u32 gen_helper_neon_min_u32
3687
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003688#define GEN_NEON_INTEGER_OP_ENV(name) do { \
3689 switch ((size << 1) | u) { \
3690 case 0: \
3691 gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \
3692 break; \
3693 case 1: \
3694 gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \
3695 break; \
3696 case 2: \
3697 gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \
3698 break; \
3699 case 3: \
3700 gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \
3701 break; \
3702 case 4: \
3703 gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \
3704 break; \
3705 case 5: \
3706 gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \
3707 break; \
3708 default: return 1; \
3709 }} while (0)
3710
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003711#define GEN_NEON_INTEGER_OP(name) do { \
3712 switch ((size << 1) | u) { \
3713 case 0: \
David 'Digit' Turner52858642011-06-03 13:41:05 +02003714 gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003715 break; \
3716 case 1: \
David 'Digit' Turner52858642011-06-03 13:41:05 +02003717 gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003718 break; \
3719 case 2: \
David 'Digit' Turner52858642011-06-03 13:41:05 +02003720 gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003721 break; \
3722 case 3: \
David 'Digit' Turner52858642011-06-03 13:41:05 +02003723 gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003724 break; \
3725 case 4: \
David 'Digit' Turner52858642011-06-03 13:41:05 +02003726 gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003727 break; \
3728 case 5: \
David 'Digit' Turner52858642011-06-03 13:41:05 +02003729 gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003730 break; \
3731 default: return 1; \
3732 }} while (0)
3733
David 'Digit' Turner52858642011-06-03 13:41:05 +02003734static TCGv neon_load_scratch(int scratch)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003735{
David 'Digit' Turner52858642011-06-03 13:41:05 +02003736 TCGv tmp = tcg_temp_new_i32();
3737 tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
3738 return tmp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003739}
3740
David 'Digit' Turner52858642011-06-03 13:41:05 +02003741static void neon_store_scratch(int scratch, TCGv var)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003742{
David 'Digit' Turner52858642011-06-03 13:41:05 +02003743 tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
3744 tcg_temp_free_i32(var);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003745}
3746
David 'Digit' Turner52858642011-06-03 13:41:05 +02003747static inline TCGv neon_get_scalar(int size, int reg)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003748{
David 'Digit' Turner52858642011-06-03 13:41:05 +02003749 TCGv tmp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003750 if (size == 1) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02003751 tmp = neon_load_reg(reg & 7, reg >> 4);
3752 if (reg & 8) {
3753 gen_neon_dup_high16(tmp);
3754 } else {
3755 gen_neon_dup_low16(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003756 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003757 } else {
3758 tmp = neon_load_reg(reg & 15, reg >> 4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003759 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003760 return tmp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003761}
3762
David 'Digit' Turner52858642011-06-03 13:41:05 +02003763static int gen_neon_unzip(int rd, int rm, int size, int q)
3764{
3765 TCGv tmp, tmp2;
3766 if (!q && size == 2) {
3767 return 1;
3768 }
3769 tmp = tcg_const_i32(rd);
3770 tmp2 = tcg_const_i32(rm);
3771 if (q) {
3772 switch (size) {
3773 case 0:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003774 gen_helper_neon_qunzip8(cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003775 break;
3776 case 1:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003777 gen_helper_neon_qunzip16(cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003778 break;
3779 case 2:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003780 gen_helper_neon_qunzip32(cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003781 break;
3782 default:
3783 abort();
3784 }
3785 } else {
3786 switch (size) {
3787 case 0:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003788 gen_helper_neon_unzip8(cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003789 break;
3790 case 1:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003791 gen_helper_neon_unzip16(cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003792 break;
3793 default:
3794 abort();
3795 }
3796 }
3797 tcg_temp_free_i32(tmp);
3798 tcg_temp_free_i32(tmp2);
3799 return 0;
3800}
3801
3802static int gen_neon_zip(int rd, int rm, int size, int q)
3803{
3804 TCGv tmp, tmp2;
3805 if (!q && size == 2) {
3806 return 1;
3807 }
3808 tmp = tcg_const_i32(rd);
3809 tmp2 = tcg_const_i32(rm);
3810 if (q) {
3811 switch (size) {
3812 case 0:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003813 gen_helper_neon_qzip8(cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003814 break;
3815 case 1:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003816 gen_helper_neon_qzip16(cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003817 break;
3818 case 2:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003819 gen_helper_neon_qzip32(cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003820 break;
3821 default:
3822 abort();
3823 }
3824 } else {
3825 switch (size) {
3826 case 0:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003827 gen_helper_neon_zip8(cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003828 break;
3829 case 1:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01003830 gen_helper_neon_zip16(cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003831 break;
3832 default:
3833 abort();
3834 }
3835 }
3836 tcg_temp_free_i32(tmp);
3837 tcg_temp_free_i32(tmp2);
3838 return 0;
3839}
3840
3841static void gen_neon_trn_u8(TCGv t0, TCGv t1)
3842{
3843 TCGv rd, tmp;
3844
3845 rd = tcg_temp_new_i32();
3846 tmp = tcg_temp_new_i32();
3847
3848 tcg_gen_shli_i32(rd, t0, 8);
3849 tcg_gen_andi_i32(rd, rd, 0xff00ff00);
3850 tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
3851 tcg_gen_or_i32(rd, rd, tmp);
3852
3853 tcg_gen_shri_i32(t1, t1, 8);
3854 tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
3855 tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
3856 tcg_gen_or_i32(t1, t1, tmp);
3857 tcg_gen_mov_i32(t0, rd);
3858
3859 tcg_temp_free_i32(tmp);
3860 tcg_temp_free_i32(rd);
3861}
3862
3863static void gen_neon_trn_u16(TCGv t0, TCGv t1)
3864{
3865 TCGv rd, tmp;
3866
3867 rd = tcg_temp_new_i32();
3868 tmp = tcg_temp_new_i32();
3869
3870 tcg_gen_shli_i32(rd, t0, 16);
3871 tcg_gen_andi_i32(tmp, t1, 0xffff);
3872 tcg_gen_or_i32(rd, rd, tmp);
3873 tcg_gen_shri_i32(t1, t1, 16);
3874 tcg_gen_andi_i32(tmp, t0, 0xffff0000);
3875 tcg_gen_or_i32(t1, t1, tmp);
3876 tcg_gen_mov_i32(t0, rd);
3877
3878 tcg_temp_free_i32(tmp);
3879 tcg_temp_free_i32(rd);
3880}
3881
3882
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003883static struct {
3884 int nregs;
3885 int interleave;
3886 int spacing;
3887} neon_ls_element_type[11] = {
3888 {4, 4, 1},
3889 {4, 4, 2},
3890 {4, 1, 1},
3891 {4, 2, 1},
3892 {3, 3, 1},
3893 {3, 3, 2},
3894 {3, 1, 1},
3895 {1, 1, 1},
3896 {2, 2, 1},
3897 {2, 2, 2},
3898 {2, 1, 1}
3899};
3900
3901/* Translate a NEON load/store element instruction. Return nonzero if the
3902 instruction is invalid. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01003903static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003904{
3905 int rd, rn, rm;
3906 int op;
3907 int nregs;
3908 int interleave;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003909 int spacing;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003910 int stride;
3911 int size;
3912 int reg;
3913 int pass;
3914 int load;
3915 int shift;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003916 TCGv addr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003917 TCGv tmp;
3918 TCGv tmp2;
3919
David 'Digit' Turner52858642011-06-03 13:41:05 +02003920 if (!s->vfp_enabled)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003921 return 1;
3922 VFP_DREG_D(rd, insn);
3923 rn = (insn >> 16) & 0xf;
3924 rm = insn & 0xf;
3925 load = (insn & (1 << 21)) != 0;
3926 if ((insn & (1 << 23)) == 0) {
3927 /* Load store all elements. */
3928 op = (insn >> 8) & 0xf;
3929 size = (insn >> 6) & 3;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003930 if (op > 10)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003931 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003932 /* Catch UNDEF cases for bad values of align field */
3933 switch (op & 0xc) {
3934 case 4:
3935 if (((insn >> 5) & 1) == 1) {
3936 return 1;
3937 }
3938 break;
3939 case 8:
3940 if (((insn >> 4) & 3) == 3) {
3941 return 1;
3942 }
3943 break;
3944 default:
3945 break;
3946 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003947 nregs = neon_ls_element_type[op].nregs;
3948 interleave = neon_ls_element_type[op].interleave;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003949 spacing = neon_ls_element_type[op].spacing;
3950 if (size == 3 && (interleave | spacing) != 1) {
3951 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003952 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003953 addr = tcg_const_i32(insn);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02003954 gen_helper_neon_vldst_all(cpu_env, addr);
David 'Digit' Turner52858642011-06-03 13:41:05 +02003955 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003956 stride = nregs * 8;
3957 } else {
3958 size = (insn >> 10) & 3;
3959 if (size == 3) {
3960 /* Load single element to all lanes. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02003961 int a = (insn >> 4) & 1;
3962 if (!load) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003963 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003964 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003965 size = (insn >> 6) & 3;
3966 nregs = ((insn >> 8) & 3) + 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02003967
3968 if (size == 3) {
3969 if (nregs != 4 || a == 0) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003970 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003971 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003972 /* For VLD4 size==3 a == 1 means 32 bits at 16 byte alignment */
3973 size = 2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08003974 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02003975 if (nregs == 1 && a == 1 && size == 0) {
3976 return 1;
3977 }
3978 if (nregs == 3 && a == 1) {
3979 return 1;
3980 }
3981 addr = tcg_temp_new_i32();
3982 load_reg_var(s, addr, rn);
3983 if (nregs == 1) {
3984 /* VLD1 to all lanes: bit 5 indicates how many Dregs to write */
3985 tmp = gen_load_and_replicate(s, addr, size);
3986 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0));
3987 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1));
3988 if (insn & (1 << 5)) {
3989 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 0));
3990 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 1));
3991 }
3992 tcg_temp_free_i32(tmp);
3993 } else {
3994 /* VLD2/3/4 to all lanes: bit 5 indicates register stride */
3995 stride = (insn & (1 << 5)) ? 2 : 1;
3996 for (reg = 0; reg < nregs; reg++) {
3997 tmp = gen_load_and_replicate(s, addr, size);
3998 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0));
3999 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1));
4000 tcg_temp_free_i32(tmp);
4001 tcg_gen_addi_i32(addr, addr, 1 << size);
4002 rd += stride;
4003 }
4004 }
4005 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004006 stride = (1 << size) * nregs;
4007 } else {
4008 /* Single element. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004009 int idx = (insn >> 4) & 0xf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004010 pass = (insn >> 7) & 1;
4011 switch (size) {
4012 case 0:
4013 shift = ((insn >> 5) & 3) * 8;
4014 stride = 1;
4015 break;
4016 case 1:
4017 shift = ((insn >> 6) & 1) * 16;
4018 stride = (insn & (1 << 5)) ? 2 : 1;
4019 break;
4020 case 2:
4021 shift = 0;
4022 stride = (insn & (1 << 6)) ? 2 : 1;
4023 break;
4024 default:
4025 abort();
4026 }
4027 nregs = ((insn >> 8) & 3) + 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004028 /* Catch the UNDEF cases. This is unavoidably a bit messy. */
4029 switch (nregs) {
4030 case 1:
4031 if (((idx & (1 << size)) != 0) ||
4032 (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) {
4033 return 1;
4034 }
4035 break;
4036 case 3:
4037 if ((idx & 1) != 0) {
4038 return 1;
4039 }
4040 /* fall through */
4041 case 2:
4042 if (size == 2 && (idx & 2) != 0) {
4043 return 1;
4044 }
4045 break;
4046 case 4:
4047 if ((size == 2) && ((idx & 3) == 3)) {
4048 return 1;
4049 }
4050 break;
4051 default:
4052 abort();
4053 }
4054 if ((rd + stride * (nregs - 1)) > 31) {
4055 /* Attempts to write off the end of the register file
4056 * are UNPREDICTABLE; we choose to UNDEF because otherwise
4057 * the neon_load_reg() would write off the end of the array.
4058 */
4059 return 1;
4060 }
4061 addr = tcg_temp_new_i32();
4062 load_reg_var(s, addr, rn);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004063 for (reg = 0; reg < nregs; reg++) {
4064 if (load) {
4065 switch (size) {
4066 case 0:
David 'Digit' Turner52858642011-06-03 13:41:05 +02004067 tmp = gen_ld8u(addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004068 break;
4069 case 1:
David 'Digit' Turner52858642011-06-03 13:41:05 +02004070 tmp = gen_ld16u(addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004071 break;
4072 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02004073 tmp = gen_ld32(addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004074 break;
4075 default: /* Avoid compiler warnings. */
4076 abort();
4077 }
4078 if (size != 2) {
4079 tmp2 = neon_load_reg(rd, pass);
4080 gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff);
David 'Digit' Turner52858642011-06-03 13:41:05 +02004081 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004082 }
4083 neon_store_reg(rd, pass, tmp);
4084 } else { /* Store */
4085 tmp = neon_load_reg(rd, pass);
4086 if (shift)
4087 tcg_gen_shri_i32(tmp, tmp, shift);
4088 switch (size) {
4089 case 0:
David 'Digit' Turner52858642011-06-03 13:41:05 +02004090 gen_st8(tmp, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004091 break;
4092 case 1:
David 'Digit' Turner52858642011-06-03 13:41:05 +02004093 gen_st16(tmp, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004094 break;
4095 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02004096 gen_st32(tmp, addr, IS_USER(s));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004097 break;
4098 }
4099 }
4100 rd += stride;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004101 tcg_gen_addi_i32(addr, addr, 1 << size);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004102 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004103 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004104 stride = nregs * (1 << size);
4105 }
4106 }
4107 if (rm != 15) {
4108 TCGv base;
4109
4110 base = load_reg(s, rn);
4111 if (rm == 13) {
4112 tcg_gen_addi_i32(base, base, stride);
4113 } else {
4114 TCGv index;
4115 index = load_reg(s, rm);
4116 tcg_gen_add_i32(base, base, index);
David 'Digit' Turner52858642011-06-03 13:41:05 +02004117 tcg_temp_free_i32(index);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004118 }
4119 store_reg(s, rn, base);
4120 }
4121 return 0;
4122}
4123
4124/* Bitwise select. dest = c ? t : f. Clobbers T and F. */
4125static void gen_neon_bsl(TCGv dest, TCGv t, TCGv f, TCGv c)
4126{
4127 tcg_gen_and_i32(t, t, c);
David 'Digit' Turner52858642011-06-03 13:41:05 +02004128 tcg_gen_andc_i32(f, f, c);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004129 tcg_gen_or_i32(dest, t, f);
4130}
4131
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07004132static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004133{
4134 switch (size) {
4135 case 0: gen_helper_neon_narrow_u8(dest, src); break;
4136 case 1: gen_helper_neon_narrow_u16(dest, src); break;
4137 case 2: tcg_gen_trunc_i64_i32(dest, src); break;
4138 default: abort();
4139 }
4140}
4141
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07004142static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004143{
4144 switch (size) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004145 case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break;
4146 case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break;
4147 case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004148 default: abort();
4149 }
4150}
4151
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07004152static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004153{
4154 switch (size) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004155 case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break;
4156 case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break;
4157 case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004158 default: abort();
4159 }
4160}
4161
4162static inline void gen_neon_unarrow_sats(int size, TCGv dest, TCGv_i64 src)
4163{
4164 switch (size) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004165 case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break;
4166 case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break;
4167 case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004168 default: abort();
4169 }
4170}
4171
4172static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift,
4173 int q, int u)
4174{
4175 if (q) {
4176 if (u) {
4177 switch (size) {
4178 case 1: gen_helper_neon_rshl_u16(var, var, shift); break;
4179 case 2: gen_helper_neon_rshl_u32(var, var, shift); break;
4180 default: abort();
4181 }
4182 } else {
4183 switch (size) {
4184 case 1: gen_helper_neon_rshl_s16(var, var, shift); break;
4185 case 2: gen_helper_neon_rshl_s32(var, var, shift); break;
4186 default: abort();
4187 }
4188 }
4189 } else {
4190 if (u) {
4191 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004192 case 1: gen_helper_neon_shl_u16(var, var, shift); break;
4193 case 2: gen_helper_neon_shl_u32(var, var, shift); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004194 default: abort();
4195 }
4196 } else {
4197 switch (size) {
4198 case 1: gen_helper_neon_shl_s16(var, var, shift); break;
4199 case 2: gen_helper_neon_shl_s32(var, var, shift); break;
4200 default: abort();
4201 }
4202 }
4203 }
4204}
4205
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07004206static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004207{
4208 if (u) {
4209 switch (size) {
4210 case 0: gen_helper_neon_widen_u8(dest, src); break;
4211 case 1: gen_helper_neon_widen_u16(dest, src); break;
4212 case 2: tcg_gen_extu_i32_i64(dest, src); break;
4213 default: abort();
4214 }
4215 } else {
4216 switch (size) {
4217 case 0: gen_helper_neon_widen_s8(dest, src); break;
4218 case 1: gen_helper_neon_widen_s16(dest, src); break;
4219 case 2: tcg_gen_ext_i32_i64(dest, src); break;
4220 default: abort();
4221 }
4222 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004223 tcg_temp_free_i32(src);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004224}
4225
4226static inline void gen_neon_addl(int size)
4227{
4228 switch (size) {
4229 case 0: gen_helper_neon_addl_u16(CPU_V001); break;
4230 case 1: gen_helper_neon_addl_u32(CPU_V001); break;
4231 case 2: tcg_gen_add_i64(CPU_V001); break;
4232 default: abort();
4233 }
4234}
4235
4236static inline void gen_neon_subl(int size)
4237{
4238 switch (size) {
4239 case 0: gen_helper_neon_subl_u16(CPU_V001); break;
4240 case 1: gen_helper_neon_subl_u32(CPU_V001); break;
4241 case 2: tcg_gen_sub_i64(CPU_V001); break;
4242 default: abort();
4243 }
4244}
4245
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07004246static inline void gen_neon_negl(TCGv_i64 var, int size)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004247{
4248 switch (size) {
4249 case 0: gen_helper_neon_negl_u16(var, var); break;
4250 case 1: gen_helper_neon_negl_u32(var, var); break;
4251 case 2: gen_helper_neon_negl_u64(var, var); break;
4252 default: abort();
4253 }
4254}
4255
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07004256static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004257{
4258 switch (size) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004259 case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break;
4260 case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004261 default: abort();
4262 }
4263}
4264
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07004265static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004266{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07004267 TCGv_i64 tmp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004268
4269 switch ((size << 1) | u) {
4270 case 0: gen_helper_neon_mull_s8(dest, a, b); break;
4271 case 1: gen_helper_neon_mull_u8(dest, a, b); break;
4272 case 2: gen_helper_neon_mull_s16(dest, a, b); break;
4273 case 3: gen_helper_neon_mull_u16(dest, a, b); break;
4274 case 4:
4275 tmp = gen_muls_i64_i32(a, b);
4276 tcg_gen_mov_i64(dest, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02004277 tcg_temp_free_i64(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004278 break;
4279 case 5:
4280 tmp = gen_mulu_i64_i32(a, b);
4281 tcg_gen_mov_i64(dest, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02004282 tcg_temp_free_i64(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004283 break;
4284 default: abort();
4285 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004286
4287 /* gen_helper_neon_mull_[su]{8|16} do not free their parameters.
4288 Don't forget to clean them now. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004289 if (size < 2) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004290 tcg_temp_free_i32(a);
4291 tcg_temp_free_i32(b);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004292 }
4293}
4294
David 'Digit' Turner52858642011-06-03 13:41:05 +02004295static void gen_neon_narrow_op(int op, int u, int size, TCGv dest, TCGv_i64 src)
4296{
4297 if (op) {
4298 if (u) {
4299 gen_neon_unarrow_sats(size, dest, src);
4300 } else {
4301 gen_neon_narrow(size, dest, src);
4302 }
4303 } else {
4304 if (u) {
4305 gen_neon_narrow_satu(size, dest, src);
4306 } else {
4307 gen_neon_narrow_sats(size, dest, src);
4308 }
4309 }
4310}
4311
4312/* Symbolic constants for op fields for Neon 3-register same-length.
4313 * The values correspond to bits [11:8,4]; see the ARM ARM DDI0406B
4314 * table A7-9.
4315 */
4316#define NEON_3R_VHADD 0
4317#define NEON_3R_VQADD 1
4318#define NEON_3R_VRHADD 2
4319#define NEON_3R_LOGIC 3 /* VAND,VBIC,VORR,VMOV,VORN,VEOR,VBIF,VBIT,VBSL */
4320#define NEON_3R_VHSUB 4
4321#define NEON_3R_VQSUB 5
4322#define NEON_3R_VCGT 6
4323#define NEON_3R_VCGE 7
4324#define NEON_3R_VSHL 8
4325#define NEON_3R_VQSHL 9
4326#define NEON_3R_VRSHL 10
4327#define NEON_3R_VQRSHL 11
4328#define NEON_3R_VMAX 12
4329#define NEON_3R_VMIN 13
4330#define NEON_3R_VABD 14
4331#define NEON_3R_VABA 15
4332#define NEON_3R_VADD_VSUB 16
4333#define NEON_3R_VTST_VCEQ 17
4334#define NEON_3R_VML 18 /* VMLA, VMLAL, VMLS, VMLSL */
4335#define NEON_3R_VMUL 19
4336#define NEON_3R_VPMAX 20
4337#define NEON_3R_VPMIN 21
4338#define NEON_3R_VQDMULH_VQRDMULH 22
4339#define NEON_3R_VPADD 23
4340#define NEON_3R_FLOAT_ARITH 26 /* float VADD, VSUB, VPADD, VABD */
4341#define NEON_3R_FLOAT_MULTIPLY 27 /* float VMLA, VMLS, VMUL */
4342#define NEON_3R_FLOAT_CMP 28 /* float VCEQ, VCGE, VCGT */
4343#define NEON_3R_FLOAT_ACMP 29 /* float VACGE, VACGT, VACLE, VACLT */
4344#define NEON_3R_FLOAT_MINMAX 30 /* float VMIN, VMAX */
4345#define NEON_3R_VRECPS_VRSQRTS 31 /* float VRECPS, VRSQRTS */
4346
4347static const uint8_t neon_3r_sizes[] = {
4348 [NEON_3R_VHADD] = 0x7,
4349 [NEON_3R_VQADD] = 0xf,
4350 [NEON_3R_VRHADD] = 0x7,
4351 [NEON_3R_LOGIC] = 0xf, /* size field encodes op type */
4352 [NEON_3R_VHSUB] = 0x7,
4353 [NEON_3R_VQSUB] = 0xf,
4354 [NEON_3R_VCGT] = 0x7,
4355 [NEON_3R_VCGE] = 0x7,
4356 [NEON_3R_VSHL] = 0xf,
4357 [NEON_3R_VQSHL] = 0xf,
4358 [NEON_3R_VRSHL] = 0xf,
4359 [NEON_3R_VQRSHL] = 0xf,
4360 [NEON_3R_VMAX] = 0x7,
4361 [NEON_3R_VMIN] = 0x7,
4362 [NEON_3R_VABD] = 0x7,
4363 [NEON_3R_VABA] = 0x7,
4364 [NEON_3R_VADD_VSUB] = 0xf,
4365 [NEON_3R_VTST_VCEQ] = 0x7,
4366 [NEON_3R_VML] = 0x7,
4367 [NEON_3R_VMUL] = 0x7,
4368 [NEON_3R_VPMAX] = 0x7,
4369 [NEON_3R_VPMIN] = 0x7,
4370 [NEON_3R_VQDMULH_VQRDMULH] = 0x6,
4371 [NEON_3R_VPADD] = 0x7,
4372 [NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */
4373 [NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */
4374 [NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */
4375 [NEON_3R_FLOAT_ACMP] = 0x5, /* size bit 1 encodes op */
4376 [NEON_3R_FLOAT_MINMAX] = 0x5, /* size bit 1 encodes op */
4377 [NEON_3R_VRECPS_VRSQRTS] = 0x5, /* size bit 1 encodes op */
4378};
4379
4380/* Symbolic constants for op fields for Neon 2-register miscellaneous.
4381 * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B
4382 * table A7-13.
4383 */
4384#define NEON_2RM_VREV64 0
4385#define NEON_2RM_VREV32 1
4386#define NEON_2RM_VREV16 2
4387#define NEON_2RM_VPADDL 4
4388#define NEON_2RM_VPADDL_U 5
4389#define NEON_2RM_VCLS 8
4390#define NEON_2RM_VCLZ 9
4391#define NEON_2RM_VCNT 10
4392#define NEON_2RM_VMVN 11
4393#define NEON_2RM_VPADAL 12
4394#define NEON_2RM_VPADAL_U 13
4395#define NEON_2RM_VQABS 14
4396#define NEON_2RM_VQNEG 15
4397#define NEON_2RM_VCGT0 16
4398#define NEON_2RM_VCGE0 17
4399#define NEON_2RM_VCEQ0 18
4400#define NEON_2RM_VCLE0 19
4401#define NEON_2RM_VCLT0 20
4402#define NEON_2RM_VABS 22
4403#define NEON_2RM_VNEG 23
4404#define NEON_2RM_VCGT0_F 24
4405#define NEON_2RM_VCGE0_F 25
4406#define NEON_2RM_VCEQ0_F 26
4407#define NEON_2RM_VCLE0_F 27
4408#define NEON_2RM_VCLT0_F 28
4409#define NEON_2RM_VABS_F 30
4410#define NEON_2RM_VNEG_F 31
4411#define NEON_2RM_VSWP 32
4412#define NEON_2RM_VTRN 33
4413#define NEON_2RM_VUZP 34
4414#define NEON_2RM_VZIP 35
4415#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */
4416#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */
4417#define NEON_2RM_VSHLL 38
4418#define NEON_2RM_VCVT_F16_F32 44
4419#define NEON_2RM_VCVT_F32_F16 46
4420#define NEON_2RM_VRECPE 56
4421#define NEON_2RM_VRSQRTE 57
4422#define NEON_2RM_VRECPE_F 58
4423#define NEON_2RM_VRSQRTE_F 59
4424#define NEON_2RM_VCVT_FS 60
4425#define NEON_2RM_VCVT_FU 61
4426#define NEON_2RM_VCVT_SF 62
4427#define NEON_2RM_VCVT_UF 63
4428
4429static int neon_2rm_is_float_op(int op)
4430{
4431 /* Return true if this neon 2reg-misc op is float-to-float */
4432 return (op == NEON_2RM_VABS_F || op == NEON_2RM_VNEG_F ||
4433 op >= NEON_2RM_VRECPE_F);
4434}
4435
4436/* Each entry in this array has bit n set if the insn allows
4437 * size value n (otherwise it will UNDEF). Since unallocated
4438 * op values will have no bits set they always UNDEF.
4439 */
4440static const uint8_t neon_2rm_sizes[] = {
4441 [NEON_2RM_VREV64] = 0x7,
4442 [NEON_2RM_VREV32] = 0x3,
4443 [NEON_2RM_VREV16] = 0x1,
4444 [NEON_2RM_VPADDL] = 0x7,
4445 [NEON_2RM_VPADDL_U] = 0x7,
4446 [NEON_2RM_VCLS] = 0x7,
4447 [NEON_2RM_VCLZ] = 0x7,
4448 [NEON_2RM_VCNT] = 0x1,
4449 [NEON_2RM_VMVN] = 0x1,
4450 [NEON_2RM_VPADAL] = 0x7,
4451 [NEON_2RM_VPADAL_U] = 0x7,
4452 [NEON_2RM_VQABS] = 0x7,
4453 [NEON_2RM_VQNEG] = 0x7,
4454 [NEON_2RM_VCGT0] = 0x7,
4455 [NEON_2RM_VCGE0] = 0x7,
4456 [NEON_2RM_VCEQ0] = 0x7,
4457 [NEON_2RM_VCLE0] = 0x7,
4458 [NEON_2RM_VCLT0] = 0x7,
4459 [NEON_2RM_VABS] = 0x7,
4460 [NEON_2RM_VNEG] = 0x7,
4461 [NEON_2RM_VCGT0_F] = 0x4,
4462 [NEON_2RM_VCGE0_F] = 0x4,
4463 [NEON_2RM_VCEQ0_F] = 0x4,
4464 [NEON_2RM_VCLE0_F] = 0x4,
4465 [NEON_2RM_VCLT0_F] = 0x4,
4466 [NEON_2RM_VABS_F] = 0x4,
4467 [NEON_2RM_VNEG_F] = 0x4,
4468 [NEON_2RM_VSWP] = 0x1,
4469 [NEON_2RM_VTRN] = 0x7,
4470 [NEON_2RM_VUZP] = 0x7,
4471 [NEON_2RM_VZIP] = 0x7,
4472 [NEON_2RM_VMOVN] = 0x7,
4473 [NEON_2RM_VQMOVN] = 0x7,
4474 [NEON_2RM_VSHLL] = 0x7,
4475 [NEON_2RM_VCVT_F16_F32] = 0x2,
4476 [NEON_2RM_VCVT_F32_F16] = 0x2,
4477 [NEON_2RM_VRECPE] = 0x4,
4478 [NEON_2RM_VRSQRTE] = 0x4,
4479 [NEON_2RM_VRECPE_F] = 0x4,
4480 [NEON_2RM_VRSQRTE_F] = 0x4,
4481 [NEON_2RM_VCVT_FS] = 0x4,
4482 [NEON_2RM_VCVT_FU] = 0x4,
4483 [NEON_2RM_VCVT_SF] = 0x4,
4484 [NEON_2RM_VCVT_UF] = 0x4,
4485};
4486
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004487/* Translate a NEON data processing instruction. Return nonzero if the
4488 instruction is invalid.
4489 We process data in a mixture of 32-bit and 64-bit chunks.
4490 Mostly we use 32-bit chunks so we can use normal scalar instructions. */
4491
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01004492static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004493{
4494 int op;
4495 int q;
4496 int rd, rn, rm;
4497 int size;
4498 int shift;
4499 int pass;
4500 int count;
4501 int pairwise;
4502 int u;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004503 uint32_t imm, mask;
4504 TCGv tmp, tmp2, tmp3, tmp4, tmp5;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07004505 TCGv_i64 tmp64;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004506
David 'Digit' Turner52858642011-06-03 13:41:05 +02004507 if (!s->vfp_enabled)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004508 return 1;
4509 q = (insn & (1 << 6)) != 0;
4510 u = (insn >> 24) & 1;
4511 VFP_DREG_D(rd, insn);
4512 VFP_DREG_N(rn, insn);
4513 VFP_DREG_M(rm, insn);
4514 size = (insn >> 20) & 3;
4515 if ((insn & (1 << 23)) == 0) {
4516 /* Three register same length. */
4517 op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02004518 /* Catch invalid op and bad size combinations: UNDEF */
4519 if ((neon_3r_sizes[op] & (1 << size)) == 0) {
4520 return 1;
4521 }
4522 /* All insns of this form UNDEF for either this condition or the
4523 * superset of cases "Q==1"; we catch the latter later.
4524 */
4525 if (q && ((rd | rn | rm) & 1)) {
4526 return 1;
4527 }
4528 if (size == 3 && op != NEON_3R_LOGIC) {
4529 /* 64-bit element instructions. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004530 for (pass = 0; pass < (q ? 2 : 1); pass++) {
4531 neon_load_reg64(cpu_V0, rn + pass);
4532 neon_load_reg64(cpu_V1, rm + pass);
4533 switch (op) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004534 case NEON_3R_VQADD:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004535 if (u) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004536 gen_helper_neon_qadd_u64(cpu_V0, cpu_env,
4537 cpu_V0, cpu_V1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004538 } else {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004539 gen_helper_neon_qadd_s64(cpu_V0, cpu_env,
4540 cpu_V0, cpu_V1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004541 }
4542 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004543 case NEON_3R_VQSUB:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004544 if (u) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004545 gen_helper_neon_qsub_u64(cpu_V0, cpu_env,
4546 cpu_V0, cpu_V1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004547 } else {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004548 gen_helper_neon_qsub_s64(cpu_V0, cpu_env,
4549 cpu_V0, cpu_V1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004550 }
4551 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004552 case NEON_3R_VSHL:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004553 if (u) {
4554 gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0);
4555 } else {
4556 gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0);
4557 }
4558 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004559 case NEON_3R_VQSHL:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004560 if (u) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004561 gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
4562 cpu_V1, cpu_V0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004563 } else {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004564 gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
4565 cpu_V1, cpu_V0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004566 }
4567 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004568 case NEON_3R_VRSHL:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004569 if (u) {
4570 gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
4571 } else {
4572 gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
4573 }
4574 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004575 case NEON_3R_VQRSHL:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004576 if (u) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004577 gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
4578 cpu_V1, cpu_V0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004579 } else {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004580 gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
4581 cpu_V1, cpu_V0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004582 }
4583 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004584 case NEON_3R_VADD_VSUB:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004585 if (u) {
4586 tcg_gen_sub_i64(CPU_V001);
4587 } else {
4588 tcg_gen_add_i64(CPU_V001);
4589 }
4590 break;
4591 default:
4592 abort();
4593 }
4594 neon_store_reg64(cpu_V0, rd + pass);
4595 }
4596 return 0;
4597 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004598 pairwise = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004599 switch (op) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004600 case NEON_3R_VSHL:
4601 case NEON_3R_VQSHL:
4602 case NEON_3R_VRSHL:
4603 case NEON_3R_VQRSHL:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004604 {
4605 int rtmp;
4606 /* Shift instruction operands are reversed. */
4607 rtmp = rn;
4608 rn = rm;
4609 rm = rtmp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004610 }
4611 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004612 case NEON_3R_VPADD:
4613 if (u) {
4614 return 1;
4615 }
4616 /* Fall through */
4617 case NEON_3R_VPMAX:
4618 case NEON_3R_VPMIN:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004619 pairwise = 1;
4620 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004621 case NEON_3R_FLOAT_ARITH:
4622 pairwise = (u && size < 2); /* if VPADD (float) */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004623 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004624 case NEON_3R_FLOAT_MINMAX:
4625 pairwise = u; /* if VPMIN/VPMAX (float) */
4626 break;
4627 case NEON_3R_FLOAT_CMP:
4628 if (!u && size) {
4629 /* no encoding for U=0 C=1x */
4630 return 1;
4631 }
4632 break;
4633 case NEON_3R_FLOAT_ACMP:
4634 if (!u) {
4635 return 1;
4636 }
4637 break;
4638 case NEON_3R_VRECPS_VRSQRTS:
4639 if (u) {
4640 return 1;
4641 }
4642 break;
4643 case NEON_3R_VMUL:
4644 if (u && (size != 0)) {
4645 /* UNDEF on invalid size for polynomial subcase */
4646 return 1;
4647 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004648 break;
4649 default:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004650 break;
4651 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004652
4653 if (pairwise && q) {
4654 /* All the pairwise insns UNDEF if Q is set */
4655 return 1;
4656 }
4657
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004658 for (pass = 0; pass < (q ? 4 : 2); pass++) {
4659
4660 if (pairwise) {
4661 /* Pairwise. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004662 if (pass < 1) {
4663 tmp = neon_load_reg(rn, 0);
4664 tmp2 = neon_load_reg(rn, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004665 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004666 tmp = neon_load_reg(rm, 0);
4667 tmp2 = neon_load_reg(rm, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004668 }
4669 } else {
4670 /* Elementwise. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004671 tmp = neon_load_reg(rn, pass);
4672 tmp2 = neon_load_reg(rm, pass);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004673 }
4674 switch (op) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004675 case NEON_3R_VHADD:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004676 GEN_NEON_INTEGER_OP(hadd);
4677 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004678 case NEON_3R_VQADD:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004679 GEN_NEON_INTEGER_OP_ENV(qadd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004680 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004681 case NEON_3R_VRHADD:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004682 GEN_NEON_INTEGER_OP(rhadd);
4683 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004684 case NEON_3R_LOGIC: /* Logic ops. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004685 switch ((u << 2) | size) {
4686 case 0: /* VAND */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004687 tcg_gen_and_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004688 break;
4689 case 1: /* BIC */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004690 tcg_gen_andc_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004691 break;
4692 case 2: /* VORR */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004693 tcg_gen_or_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004694 break;
4695 case 3: /* VORN */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004696 tcg_gen_orc_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004697 break;
4698 case 4: /* VEOR */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004699 tcg_gen_xor_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004700 break;
4701 case 5: /* VBSL */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004702 tmp3 = neon_load_reg(rd, pass);
4703 gen_neon_bsl(tmp, tmp, tmp2, tmp3);
4704 tcg_temp_free_i32(tmp3);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004705 break;
4706 case 6: /* VBIT */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004707 tmp3 = neon_load_reg(rd, pass);
4708 gen_neon_bsl(tmp, tmp, tmp3, tmp2);
4709 tcg_temp_free_i32(tmp3);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004710 break;
4711 case 7: /* VBIF */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004712 tmp3 = neon_load_reg(rd, pass);
4713 gen_neon_bsl(tmp, tmp3, tmp, tmp2);
4714 tcg_temp_free_i32(tmp3);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004715 break;
4716 }
4717 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004718 case NEON_3R_VHSUB:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004719 GEN_NEON_INTEGER_OP(hsub);
4720 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004721 case NEON_3R_VQSUB:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004722 GEN_NEON_INTEGER_OP_ENV(qsub);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004723 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004724 case NEON_3R_VCGT:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004725 GEN_NEON_INTEGER_OP(cgt);
4726 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004727 case NEON_3R_VCGE:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004728 GEN_NEON_INTEGER_OP(cge);
4729 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004730 case NEON_3R_VSHL:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004731 GEN_NEON_INTEGER_OP(shl);
4732 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004733 case NEON_3R_VQSHL:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004734 GEN_NEON_INTEGER_OP_ENV(qshl);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004735 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004736 case NEON_3R_VRSHL:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004737 GEN_NEON_INTEGER_OP(rshl);
4738 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004739 case NEON_3R_VQRSHL:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004740 GEN_NEON_INTEGER_OP_ENV(qrshl);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004741 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004742 case NEON_3R_VMAX:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004743 GEN_NEON_INTEGER_OP(max);
4744 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004745 case NEON_3R_VMIN:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004746 GEN_NEON_INTEGER_OP(min);
4747 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004748 case NEON_3R_VABD:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004749 GEN_NEON_INTEGER_OP(abd);
4750 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004751 case NEON_3R_VABA:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004752 GEN_NEON_INTEGER_OP(abd);
David 'Digit' Turner52858642011-06-03 13:41:05 +02004753 tcg_temp_free_i32(tmp2);
4754 tmp2 = neon_load_reg(rd, pass);
4755 gen_neon_add(size, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004756 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004757 case NEON_3R_VADD_VSUB:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004758 if (!u) { /* VADD */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004759 gen_neon_add(size, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004760 } else { /* VSUB */
4761 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004762 case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break;
4763 case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break;
4764 case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break;
4765 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004766 }
4767 }
4768 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004769 case NEON_3R_VTST_VCEQ:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004770 if (!u) { /* VTST */
4771 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004772 case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break;
4773 case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break;
4774 case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break;
4775 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004776 }
4777 } else { /* VCEQ */
4778 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004779 case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
4780 case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
4781 case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
4782 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004783 }
4784 }
4785 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004786 case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004787 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004788 case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
4789 case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
4790 case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
4791 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004792 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004793 tcg_temp_free_i32(tmp2);
4794 tmp2 = neon_load_reg(rd, pass);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004795 if (u) { /* VMLS */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004796 gen_neon_rsb(size, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004797 } else { /* VMLA */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004798 gen_neon_add(size, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004799 }
4800 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004801 case NEON_3R_VMUL:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004802 if (u) { /* polynomial */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004803 gen_helper_neon_mul_p8(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004804 } else { /* Integer */
4805 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004806 case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
4807 case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
4808 case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
4809 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004810 }
4811 }
4812 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004813 case NEON_3R_VPMAX:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004814 GEN_NEON_INTEGER_OP(pmax);
4815 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004816 case NEON_3R_VPMIN:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004817 GEN_NEON_INTEGER_OP(pmin);
4818 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004819 case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004820 if (!u) { /* VQDMULH */
4821 switch (size) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004822 case 1:
4823 gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
4824 break;
4825 case 2:
4826 gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
4827 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004828 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004829 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004830 } else { /* VQRDMULH */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004831 switch (size) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01004832 case 1:
4833 gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
4834 break;
4835 case 2:
4836 gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
4837 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004838 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004839 }
4840 }
4841 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004842 case NEON_3R_VPADD:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004843 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004844 case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break;
4845 case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break;
4846 case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break;
4847 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004848 }
4849 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02004850 case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */
David 'Digit' Turner16998982014-03-18 17:23:07 +01004851 {
4852 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004853 switch ((u << 2) | size) {
4854 case 0: /* VADD */
David 'Digit' Turner16998982014-03-18 17:23:07 +01004855 case 4: /* VPADD */
4856 gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004857 break;
4858 case 2: /* VSUB */
David 'Digit' Turner16998982014-03-18 17:23:07 +01004859 gen_helper_vfp_subs(tmp, tmp, tmp2, fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004860 break;
4861 case 6: /* VABD */
David 'Digit' Turner16998982014-03-18 17:23:07 +01004862 gen_helper_neon_abd_f32(tmp, tmp, tmp2, fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004863 break;
4864 default:
David 'Digit' Turner52858642011-06-03 13:41:05 +02004865 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004866 }
David 'Digit' Turner16998982014-03-18 17:23:07 +01004867 tcg_temp_free_ptr(fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004868 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01004869 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004870 case NEON_3R_FLOAT_MULTIPLY:
David 'Digit' Turner16998982014-03-18 17:23:07 +01004871 {
4872 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
4873 gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004874 if (!u) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004875 tcg_temp_free_i32(tmp2);
4876 tmp2 = neon_load_reg(rd, pass);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004877 if (size == 0) {
David 'Digit' Turner16998982014-03-18 17:23:07 +01004878 gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004879 } else {
David 'Digit' Turner16998982014-03-18 17:23:07 +01004880 gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004881 }
4882 }
David 'Digit' Turner16998982014-03-18 17:23:07 +01004883 tcg_temp_free_ptr(fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004884 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01004885 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004886 case NEON_3R_FLOAT_CMP:
David 'Digit' Turner16998982014-03-18 17:23:07 +01004887 {
4888 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004889 if (!u) {
David 'Digit' Turner16998982014-03-18 17:23:07 +01004890 gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004891 } else {
David 'Digit' Turner16998982014-03-18 17:23:07 +01004892 if (size == 0) {
4893 gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
4894 } else {
4895 gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
4896 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004897 }
David 'Digit' Turner16998982014-03-18 17:23:07 +01004898 tcg_temp_free_ptr(fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004899 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01004900 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004901 case NEON_3R_FLOAT_ACMP:
David 'Digit' Turner16998982014-03-18 17:23:07 +01004902 {
4903 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
4904 if (size == 0) {
4905 gen_helper_neon_acge_f32(tmp, tmp, tmp2, fpstatus);
4906 } else {
4907 gen_helper_neon_acgt_f32(tmp, tmp, tmp2, fpstatus);
4908 }
4909 tcg_temp_free_ptr(fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004910 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01004911 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004912 case NEON_3R_FLOAT_MINMAX:
David 'Digit' Turner16998982014-03-18 17:23:07 +01004913 {
4914 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
4915 if (size == 0) {
4916 gen_helper_neon_max_f32(tmp, tmp, tmp2, fpstatus);
4917 } else {
4918 gen_helper_neon_min_f32(tmp, tmp, tmp2, fpstatus);
4919 }
4920 tcg_temp_free_ptr(fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004921 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01004922 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004923 case NEON_3R_VRECPS_VRSQRTS:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004924 if (size == 0)
David 'Digit' Turner52858642011-06-03 13:41:05 +02004925 gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004926 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02004927 gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004928 break;
4929 default:
4930 abort();
4931 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02004932 tcg_temp_free_i32(tmp2);
4933
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004934 /* Save the result. For elementwise operations we can put it
4935 straight into the destination register. For pairwise operations
4936 we have to be careful to avoid clobbering the source operands. */
4937 if (pairwise && rd == rm) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004938 neon_store_scratch(pass, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004939 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004940 neon_store_reg(rd, pass, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004941 }
4942
4943 } /* for pass */
4944 if (pairwise && rd == rm) {
4945 for (pass = 0; pass < (q ? 4 : 2); pass++) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004946 tmp = neon_load_scratch(pass);
4947 neon_store_reg(rd, pass, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004948 }
4949 }
4950 /* End of 3 register same size operations. */
4951 } else if (insn & (1 << 4)) {
4952 if ((insn & 0x00380080) != 0) {
4953 /* Two registers and shift. */
4954 op = (insn >> 8) & 0xf;
4955 if (insn & (1 << 7)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02004956 /* 64-bit shift. */
4957 if (op > 7) {
4958 return 1;
4959 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004960 size = 3;
4961 } else {
4962 size = 2;
4963 while ((insn & (1 << (size + 19))) == 0)
4964 size--;
4965 }
4966 shift = (insn >> 16) & ((1 << (3 + size)) - 1);
4967 /* To avoid excessive dumplication of ops we implement shift
4968 by immediate using the variable shift operations. */
4969 if (op < 8) {
4970 /* Shift by immediate:
4971 VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02004972 if (q && ((rd | rm) & 1)) {
4973 return 1;
4974 }
4975 if (!u && (op == 4 || op == 6)) {
4976 return 1;
4977 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08004978 /* Right shifts are encoded as N - shift, where N is the
4979 element size in bits. */
4980 if (op <= 4)
4981 shift = shift - (1 << (size + 3));
4982 if (size == 3) {
4983 count = q + 1;
4984 } else {
4985 count = q ? 4: 2;
4986 }
4987 switch (size) {
4988 case 0:
4989 imm = (uint8_t) shift;
4990 imm |= imm << 8;
4991 imm |= imm << 16;
4992 break;
4993 case 1:
4994 imm = (uint16_t) shift;
4995 imm |= imm << 16;
4996 break;
4997 case 2:
4998 case 3:
4999 imm = shift;
5000 break;
5001 default:
5002 abort();
5003 }
5004
5005 for (pass = 0; pass < count; pass++) {
5006 if (size == 3) {
5007 neon_load_reg64(cpu_V0, rm + pass);
5008 tcg_gen_movi_i64(cpu_V1, imm);
5009 switch (op) {
5010 case 0: /* VSHR */
5011 case 1: /* VSRA */
5012 if (u)
5013 gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
5014 else
5015 gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
5016 break;
5017 case 2: /* VRSHR */
5018 case 3: /* VRSRA */
5019 if (u)
5020 gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
5021 else
5022 gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
5023 break;
5024 case 4: /* VSRI */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005025 case 5: /* VSHL, VSLI */
5026 gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
5027 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005028 case 6: /* VQSHLU */
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005029 gen_helper_neon_qshlu_s64(cpu_V0, cpu_env,
5030 cpu_V0, cpu_V1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005031 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005032 case 7: /* VQSHL */
5033 if (u) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005034 gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
David 'Digit' Turner52858642011-06-03 13:41:05 +02005035 cpu_V0, cpu_V1);
5036 } else {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005037 gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
David 'Digit' Turner52858642011-06-03 13:41:05 +02005038 cpu_V0, cpu_V1);
5039 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005040 break;
5041 }
5042 if (op == 1 || op == 3) {
5043 /* Accumulate. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005044 neon_load_reg64(cpu_V1, rd + pass);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005045 tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
5046 } else if (op == 4 || (op == 5 && u)) {
5047 /* Insert */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005048 neon_load_reg64(cpu_V1, rd + pass);
5049 uint64_t mask;
5050 if (shift < -63 || shift > 63) {
5051 mask = 0;
5052 } else {
5053 if (op == 4) {
5054 mask = 0xffffffffffffffffull >> -shift;
5055 } else {
5056 mask = 0xffffffffffffffffull << shift;
5057 }
5058 }
5059 tcg_gen_andi_i64(cpu_V1, cpu_V1, ~mask);
5060 tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005061 }
5062 neon_store_reg64(cpu_V0, rd + pass);
5063 } else { /* size < 3 */
5064 /* Operands in T0 and T1. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005065 tmp = neon_load_reg(rm, pass);
5066 tmp2 = tcg_const_i32(imm);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005067 switch (op) {
5068 case 0: /* VSHR */
5069 case 1: /* VSRA */
5070 GEN_NEON_INTEGER_OP(shl);
5071 break;
5072 case 2: /* VRSHR */
5073 case 3: /* VRSRA */
5074 GEN_NEON_INTEGER_OP(rshl);
5075 break;
5076 case 4: /* VSRI */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005077 case 5: /* VSHL, VSLI */
5078 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005079 case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break;
5080 case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break;
5081 case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break;
5082 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005083 }
5084 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005085 case 6: /* VQSHLU */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005086 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005087 case 0:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005088 gen_helper_neon_qshlu_s8(tmp, cpu_env,
5089 tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005090 break;
5091 case 1:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005092 gen_helper_neon_qshlu_s16(tmp, cpu_env,
5093 tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005094 break;
5095 case 2:
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005096 gen_helper_neon_qshlu_s32(tmp, cpu_env,
5097 tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005098 break;
5099 default:
5100 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005101 }
5102 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005103 case 7: /* VQSHL */
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005104 GEN_NEON_INTEGER_OP_ENV(qshl);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005105 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005106 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005107 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005108
5109 if (op == 1 || op == 3) {
5110 /* Accumulate. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005111 tmp2 = neon_load_reg(rd, pass);
5112 gen_neon_add(size, tmp, tmp2);
5113 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005114 } else if (op == 4 || (op == 5 && u)) {
5115 /* Insert */
5116 switch (size) {
5117 case 0:
5118 if (op == 4)
David 'Digit' Turner52858642011-06-03 13:41:05 +02005119 mask = 0xff >> -shift;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005120 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02005121 mask = (uint8_t)(0xff << shift);
5122 mask |= mask << 8;
5123 mask |= mask << 16;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005124 break;
5125 case 1:
5126 if (op == 4)
David 'Digit' Turner52858642011-06-03 13:41:05 +02005127 mask = 0xffff >> -shift;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005128 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02005129 mask = (uint16_t)(0xffff << shift);
5130 mask |= mask << 16;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005131 break;
5132 case 2:
David 'Digit' Turner52858642011-06-03 13:41:05 +02005133 if (shift < -31 || shift > 31) {
5134 mask = 0;
5135 } else {
5136 if (op == 4)
5137 mask = 0xffffffffu >> -shift;
5138 else
5139 mask = 0xffffffffu << shift;
5140 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005141 break;
5142 default:
5143 abort();
5144 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005145 tmp2 = neon_load_reg(rd, pass);
5146 tcg_gen_andi_i32(tmp, tmp, mask);
5147 tcg_gen_andi_i32(tmp2, tmp2, ~mask);
5148 tcg_gen_or_i32(tmp, tmp, tmp2);
5149 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005150 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005151 neon_store_reg(rd, pass, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005152 }
5153 } /* for pass */
5154 } else if (op < 10) {
5155 /* Shift by immediate and narrow:
5156 VSHRN, VRSHRN, VQSHRN, VQRSHRN. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005157 int input_unsigned = (op == 8) ? !u : u;
5158 if (rm & 1) {
5159 return 1;
5160 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005161 shift = shift - (1 << (size + 3));
5162 size++;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005163 if (size == 3) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005164 tmp64 = tcg_const_i64(shift);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005165 neon_load_reg64(cpu_V0, rm);
5166 neon_load_reg64(cpu_V1, rm + 1);
5167 for (pass = 0; pass < 2; pass++) {
5168 TCGv_i64 in;
5169 if (pass == 0) {
5170 in = cpu_V0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005171 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005172 in = cpu_V1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005173 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005174 if (q) {
5175 if (input_unsigned) {
5176 gen_helper_neon_rshl_u64(cpu_V0, in, tmp64);
5177 } else {
5178 gen_helper_neon_rshl_s64(cpu_V0, in, tmp64);
5179 }
5180 } else {
5181 if (input_unsigned) {
5182 gen_helper_neon_shl_u64(cpu_V0, in, tmp64);
5183 } else {
5184 gen_helper_neon_shl_s64(cpu_V0, in, tmp64);
5185 }
5186 }
5187 tmp = tcg_temp_new_i32();
5188 gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
5189 neon_store_reg(rd, pass, tmp);
5190 } /* for pass */
5191 tcg_temp_free_i64(tmp64);
5192 } else {
5193 if (size == 1) {
5194 imm = (uint16_t)shift;
5195 imm |= imm << 16;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005196 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005197 /* size == 2 */
5198 imm = (uint32_t)shift;
5199 }
5200 tmp2 = tcg_const_i32(imm);
5201 tmp4 = neon_load_reg(rm + 1, 0);
5202 tmp5 = neon_load_reg(rm + 1, 1);
5203 for (pass = 0; pass < 2; pass++) {
5204 if (pass == 0) {
5205 tmp = neon_load_reg(rm, 0);
5206 } else {
5207 tmp = tmp4;
5208 }
5209 gen_neon_shift_narrow(size, tmp, tmp2, q,
5210 input_unsigned);
5211 if (pass == 0) {
5212 tmp3 = neon_load_reg(rm, 1);
5213 } else {
5214 tmp3 = tmp5;
5215 }
5216 gen_neon_shift_narrow(size, tmp3, tmp2, q,
5217 input_unsigned);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005218 tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005219 tcg_temp_free_i32(tmp);
5220 tcg_temp_free_i32(tmp3);
5221 tmp = tcg_temp_new_i32();
5222 gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
5223 neon_store_reg(rd, pass, tmp);
5224 } /* for pass */
5225 tcg_temp_free_i32(tmp2);
5226 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005227 } else if (op == 10) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005228 /* VSHLL, VMOVL */
5229 if (q || (rd & 1)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005230 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005231 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005232 tmp = neon_load_reg(rm, 0);
5233 tmp2 = neon_load_reg(rm, 1);
5234 for (pass = 0; pass < 2; pass++) {
5235 if (pass == 1)
5236 tmp = tmp2;
5237
5238 gen_neon_widen(cpu_V0, tmp, size, u);
5239
5240 if (shift != 0) {
5241 /* The shift is less than the width of the source
5242 type, so we can just shift the whole register. */
5243 tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005244 /* Widen the result of shift: we need to clear
5245 * the potential overflow bits resulting from
5246 * left bits of the narrow input appearing as
5247 * right bits of left the neighbour narrow
5248 * input. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005249 if (size < 2 || !u) {
5250 uint64_t imm64;
5251 if (size == 0) {
5252 imm = (0xffu >> (8 - shift));
5253 imm |= imm << 16;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005254 } else if (size == 1) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005255 imm = 0xffff >> (16 - shift);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005256 } else {
5257 /* size == 2 */
5258 imm = 0xffffffff >> (32 - shift);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005259 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005260 if (size < 2) {
5261 imm64 = imm | (((uint64_t)imm) << 32);
5262 } else {
5263 imm64 = imm;
5264 }
5265 tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005266 }
5267 }
5268 neon_store_reg64(cpu_V0, rd + pass);
5269 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005270 } else if (op >= 14) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005271 /* VCVT fixed-point. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005272 if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
5273 return 1;
5274 }
5275 /* We have already masked out the must-be-1 top bit of imm6,
5276 * hence this 32-shift where the ARM ARM has 64-imm6.
5277 */
5278 shift = 32 - shift;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005279 for (pass = 0; pass < (q ? 4 : 2); pass++) {
5280 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
David 'Digit' Turner52858642011-06-03 13:41:05 +02005281 if (!(op & 1)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005282 if (u)
David 'Digit' Turner52858642011-06-03 13:41:05 +02005283 gen_vfp_ulto(0, shift, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005284 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02005285 gen_vfp_slto(0, shift, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005286 } else {
5287 if (u)
David 'Digit' Turner52858642011-06-03 13:41:05 +02005288 gen_vfp_toul(0, shift, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005289 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02005290 gen_vfp_tosl(0, shift, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005291 }
5292 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
5293 }
5294 } else {
5295 return 1;
5296 }
5297 } else { /* (insn & 0x00380080) == 0 */
5298 int invert;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005299 if (q && (rd & 1)) {
5300 return 1;
5301 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005302
5303 op = (insn >> 8) & 0xf;
5304 /* One register and immediate. */
5305 imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
5306 invert = (insn & (1 << 5)) != 0;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005307 /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
5308 * We choose to not special-case this and will behave as if a
5309 * valid constant encoding of 0 had been given.
5310 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005311 switch (op) {
5312 case 0: case 1:
5313 /* no-op */
5314 break;
5315 case 2: case 3:
5316 imm <<= 8;
5317 break;
5318 case 4: case 5:
5319 imm <<= 16;
5320 break;
5321 case 6: case 7:
5322 imm <<= 24;
5323 break;
5324 case 8: case 9:
5325 imm |= imm << 16;
5326 break;
5327 case 10: case 11:
5328 imm = (imm << 8) | (imm << 24);
5329 break;
5330 case 12:
David 'Digit' Turner52858642011-06-03 13:41:05 +02005331 imm = (imm << 8) | 0xff;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005332 break;
5333 case 13:
5334 imm = (imm << 16) | 0xffff;
5335 break;
5336 case 14:
5337 imm |= (imm << 8) | (imm << 16) | (imm << 24);
5338 if (invert)
5339 imm = ~imm;
5340 break;
5341 case 15:
David 'Digit' Turner52858642011-06-03 13:41:05 +02005342 if (invert) {
5343 return 1;
5344 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005345 imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
5346 | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
5347 break;
5348 }
5349 if (invert)
5350 imm = ~imm;
5351
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005352 for (pass = 0; pass < (q ? 4 : 2); pass++) {
5353 if (op & 1 && op < 12) {
5354 tmp = neon_load_reg(rd, pass);
5355 if (invert) {
5356 /* The immediate value has already been inverted, so
5357 BIC becomes AND. */
5358 tcg_gen_andi_i32(tmp, tmp, imm);
5359 } else {
5360 tcg_gen_ori_i32(tmp, tmp, imm);
5361 }
5362 } else {
5363 /* VMOV, VMVN. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005364 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005365 if (op == 14 && invert) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005366 int n;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005367 uint32_t val;
5368 val = 0;
5369 for (n = 0; n < 4; n++) {
5370 if (imm & (1 << (n + (pass & 1) * 4)))
5371 val |= 0xff << (n * 8);
5372 }
5373 tcg_gen_movi_i32(tmp, val);
5374 } else {
5375 tcg_gen_movi_i32(tmp, imm);
5376 }
5377 }
5378 neon_store_reg(rd, pass, tmp);
5379 }
5380 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005381 } else { /* (insn & 0x00800010 == 0x00800000) */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005382 if (size != 3) {
5383 op = (insn >> 8) & 0xf;
5384 if ((insn & (1 << 6)) == 0) {
5385 /* Three registers of different lengths. */
5386 int src1_wide;
5387 int src2_wide;
5388 int prewiden;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005389 /* undefreq: bit 0 : UNDEF if size != 0
5390 * bit 1 : UNDEF if size == 0
5391 * bit 2 : UNDEF if U == 1
5392 * Note that [1:0] set implies 'always UNDEF'
5393 */
5394 int undefreq;
5395 /* prewiden, src1_wide, src2_wide, undefreq */
5396 static const int neon_3reg_wide[16][4] = {
5397 {1, 0, 0, 0}, /* VADDL */
5398 {1, 1, 0, 0}, /* VADDW */
5399 {1, 0, 0, 0}, /* VSUBL */
5400 {1, 1, 0, 0}, /* VSUBW */
5401 {0, 1, 1, 0}, /* VADDHN */
5402 {0, 0, 0, 0}, /* VABAL */
5403 {0, 1, 1, 0}, /* VSUBHN */
5404 {0, 0, 0, 0}, /* VABDL */
5405 {0, 0, 0, 0}, /* VMLAL */
5406 {0, 0, 0, 6}, /* VQDMLAL */
5407 {0, 0, 0, 0}, /* VMLSL */
5408 {0, 0, 0, 6}, /* VQDMLSL */
5409 {0, 0, 0, 0}, /* Integer VMULL */
5410 {0, 0, 0, 2}, /* VQDMULL */
5411 {0, 0, 0, 5}, /* Polynomial VMULL */
5412 {0, 0, 0, 3}, /* Reserved: always UNDEF */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005413 };
5414
5415 prewiden = neon_3reg_wide[op][0];
5416 src1_wide = neon_3reg_wide[op][1];
5417 src2_wide = neon_3reg_wide[op][2];
David 'Digit' Turner52858642011-06-03 13:41:05 +02005418 undefreq = neon_3reg_wide[op][3];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005419
David 'Digit' Turner52858642011-06-03 13:41:05 +02005420 if (((undefreq & 1) && (size != 0)) ||
5421 ((undefreq & 2) && (size == 0)) ||
5422 ((undefreq & 4) && u)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005423 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005424 }
5425 if ((src1_wide && (rn & 1)) ||
5426 (src2_wide && (rm & 1)) ||
5427 (!src2_wide && (rd & 1))) {
5428 return 1;
5429 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005430
5431 /* Avoid overlapping operands. Wide source operands are
5432 always aligned so will never overlap with wide
5433 destinations in problematic ways. */
5434 if (rd == rm && !src2_wide) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005435 tmp = neon_load_reg(rm, 1);
5436 neon_store_scratch(2, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005437 } else if (rd == rn && !src1_wide) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005438 tmp = neon_load_reg(rn, 1);
5439 neon_store_scratch(2, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005440 }
5441 TCGV_UNUSED(tmp3);
5442 for (pass = 0; pass < 2; pass++) {
5443 if (src1_wide) {
5444 neon_load_reg64(cpu_V0, rn + pass);
5445 TCGV_UNUSED(tmp);
5446 } else {
5447 if (pass == 1 && rd == rn) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005448 tmp = neon_load_scratch(2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005449 } else {
5450 tmp = neon_load_reg(rn, pass);
5451 }
5452 if (prewiden) {
5453 gen_neon_widen(cpu_V0, tmp, size, u);
5454 }
5455 }
5456 if (src2_wide) {
5457 neon_load_reg64(cpu_V1, rm + pass);
5458 TCGV_UNUSED(tmp2);
5459 } else {
5460 if (pass == 1 && rd == rm) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005461 tmp2 = neon_load_scratch(2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005462 } else {
5463 tmp2 = neon_load_reg(rm, pass);
5464 }
5465 if (prewiden) {
5466 gen_neon_widen(cpu_V1, tmp2, size, u);
5467 }
5468 }
5469 switch (op) {
5470 case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
5471 gen_neon_addl(size);
5472 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005473 case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHN, VRSUBHN */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005474 gen_neon_subl(size);
5475 break;
5476 case 5: case 7: /* VABAL, VABDL */
5477 switch ((size << 1) | u) {
5478 case 0:
5479 gen_helper_neon_abdl_s16(cpu_V0, tmp, tmp2);
5480 break;
5481 case 1:
5482 gen_helper_neon_abdl_u16(cpu_V0, tmp, tmp2);
5483 break;
5484 case 2:
5485 gen_helper_neon_abdl_s32(cpu_V0, tmp, tmp2);
5486 break;
5487 case 3:
5488 gen_helper_neon_abdl_u32(cpu_V0, tmp, tmp2);
5489 break;
5490 case 4:
5491 gen_helper_neon_abdl_s64(cpu_V0, tmp, tmp2);
5492 break;
5493 case 5:
5494 gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2);
5495 break;
5496 default: abort();
5497 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005498 tcg_temp_free_i32(tmp2);
5499 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005500 break;
5501 case 8: case 9: case 10: case 11: case 12: case 13:
5502 /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
5503 gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
5504 break;
5505 case 14: /* Polynomial VMULL */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005506 gen_helper_neon_mull_p8(cpu_V0, tmp, tmp2);
5507 tcg_temp_free_i32(tmp2);
5508 tcg_temp_free_i32(tmp);
5509 break;
5510 default: /* 15 is RESERVED: caught earlier */
5511 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005512 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005513 if (op == 13) {
5514 /* VQDMULL */
5515 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
5516 neon_store_reg64(cpu_V0, rd + pass);
5517 } else if (op == 5 || (op >= 8 && op <= 11)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005518 /* Accumulate. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005519 neon_load_reg64(cpu_V1, rd + pass);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005520 switch (op) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005521 case 10: /* VMLSL */
5522 gen_neon_negl(cpu_V0, size);
5523 /* Fall through */
5524 case 5: case 8: /* VABAL, VMLAL */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005525 gen_neon_addl(size);
5526 break;
5527 case 9: case 11: /* VQDMLAL, VQDMLSL */
5528 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005529 if (op == 11) {
5530 gen_neon_negl(cpu_V0, size);
5531 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005532 gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
5533 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005534 default:
5535 abort();
5536 }
5537 neon_store_reg64(cpu_V0, rd + pass);
5538 } else if (op == 4 || op == 6) {
5539 /* Narrowing operation. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005540 tmp = tcg_temp_new_i32();
5541 if (!u) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005542 switch (size) {
5543 case 0:
5544 gen_helper_neon_narrow_high_u8(tmp, cpu_V0);
5545 break;
5546 case 1:
5547 gen_helper_neon_narrow_high_u16(tmp, cpu_V0);
5548 break;
5549 case 2:
5550 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
5551 tcg_gen_trunc_i64_i32(tmp, cpu_V0);
5552 break;
5553 default: abort();
5554 }
5555 } else {
5556 switch (size) {
5557 case 0:
5558 gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0);
5559 break;
5560 case 1:
5561 gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0);
5562 break;
5563 case 2:
5564 tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31);
5565 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
5566 tcg_gen_trunc_i64_i32(tmp, cpu_V0);
5567 break;
5568 default: abort();
5569 }
5570 }
5571 if (pass == 0) {
5572 tmp3 = tmp;
5573 } else {
5574 neon_store_reg(rd, 0, tmp3);
5575 neon_store_reg(rd, 1, tmp);
5576 }
5577 } else {
5578 /* Write back the result. */
5579 neon_store_reg64(cpu_V0, rd + pass);
5580 }
5581 }
5582 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005583 /* Two registers and a scalar. NB that for ops of this form
5584 * the ARM ARM labels bit 24 as Q, but it is in our variable
5585 * 'u', not 'q'.
5586 */
5587 if (size == 0) {
5588 return 1;
5589 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005590 switch (op) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005591 case 1: /* Float VMLA scalar */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005592 case 5: /* Floating point VMLS scalar */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005593 case 9: /* Floating point VMUL scalar */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005594 if (size == 1) {
5595 return 1;
5596 }
5597 /* fall through */
5598 case 0: /* Integer VMLA scalar */
5599 case 4: /* Integer VMLS scalar */
5600 case 8: /* Integer VMUL scalar */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005601 case 12: /* VQDMULH scalar */
5602 case 13: /* VQRDMULH scalar */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005603 if (u && ((rd | rn) & 1)) {
5604 return 1;
5605 }
5606 tmp = neon_get_scalar(size, rm);
5607 neon_store_scratch(0, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005608 for (pass = 0; pass < (u ? 4 : 2); pass++) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005609 tmp = neon_load_scratch(0);
5610 tmp2 = neon_load_reg(rn, pass);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005611 if (op == 12) {
5612 if (size == 1) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005613 gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005614 } else {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005615 gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005616 }
5617 } else if (op == 13) {
5618 if (size == 1) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005619 gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005620 } else {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005621 gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005622 }
5623 } else if (op & 1) {
David 'Digit' Turner16998982014-03-18 17:23:07 +01005624 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
5625 gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
5626 tcg_temp_free_ptr(fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005627 } else {
5628 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005629 case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
5630 case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
5631 case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
5632 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005633 }
5634 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005635 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005636 if (op < 8) {
5637 /* Accumulate. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005638 tmp2 = neon_load_reg(rd, pass);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005639 switch (op) {
5640 case 0:
David 'Digit' Turner52858642011-06-03 13:41:05 +02005641 gen_neon_add(size, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005642 break;
5643 case 1:
David 'Digit' Turner16998982014-03-18 17:23:07 +01005644 {
5645 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
5646 gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
5647 tcg_temp_free_ptr(fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005648 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01005649 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005650 case 4:
David 'Digit' Turner52858642011-06-03 13:41:05 +02005651 gen_neon_rsb(size, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005652 break;
5653 case 5:
David 'Digit' Turner16998982014-03-18 17:23:07 +01005654 {
5655 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
5656 gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
5657 tcg_temp_free_ptr(fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005658 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01005659 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005660 default:
5661 abort();
5662 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005663 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005664 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005665 neon_store_reg(rd, pass, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005666 }
5667 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005668 case 3: /* VQDMLAL scalar */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005669 case 7: /* VQDMLSL scalar */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005670 case 11: /* VQDMULL scalar */
David 'Digit' Turner52858642011-06-03 13:41:05 +02005671 if (u == 1) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005672 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005673 }
5674 /* fall through */
5675 case 2: /* VMLAL sclar */
5676 case 6: /* VMLSL scalar */
5677 case 10: /* VMULL scalar */
5678 if (rd & 1) {
5679 return 1;
5680 }
5681 tmp2 = neon_get_scalar(size, rm);
5682 /* We need a copy of tmp2 because gen_neon_mull
5683 * deletes it during pass 0. */
5684 tmp4 = tcg_temp_new_i32();
5685 tcg_gen_mov_i32(tmp4, tmp2);
5686 tmp3 = neon_load_reg(rn, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005687
5688 for (pass = 0; pass < 2; pass++) {
5689 if (pass == 0) {
5690 tmp = neon_load_reg(rn, 0);
5691 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005692 tmp = tmp3;
5693 tmp2 = tmp4;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005694 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005695 gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005696 if (op != 11) {
5697 neon_load_reg64(cpu_V1, rd + pass);
5698 }
5699 switch (op) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005700 case 6:
5701 gen_neon_negl(cpu_V0, size);
5702 /* Fall through */
5703 case 2:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005704 gen_neon_addl(size);
5705 break;
5706 case 3: case 7:
5707 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005708 if (op == 7) {
5709 gen_neon_negl(cpu_V0, size);
5710 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005711 gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
5712 break;
5713 case 10:
5714 /* no-op */
5715 break;
5716 case 11:
5717 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
5718 break;
5719 default:
5720 abort();
5721 }
5722 neon_store_reg64(cpu_V0, rd + pass);
5723 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005724
5725
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005726 break;
5727 default: /* 14 and 15 are RESERVED */
5728 return 1;
5729 }
5730 }
5731 } else { /* size == 3 */
5732 if (!u) {
5733 /* Extract. */
5734 imm = (insn >> 8) & 0xf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005735
5736 if (imm > 7 && !q)
5737 return 1;
5738
David 'Digit' Turner52858642011-06-03 13:41:05 +02005739 if (q && ((rd | rn | rm) & 1)) {
5740 return 1;
5741 }
5742
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005743 if (imm == 0) {
5744 neon_load_reg64(cpu_V0, rn);
5745 if (q) {
5746 neon_load_reg64(cpu_V1, rn + 1);
5747 }
5748 } else if (imm == 8) {
5749 neon_load_reg64(cpu_V0, rn + 1);
5750 if (q) {
5751 neon_load_reg64(cpu_V1, rm);
5752 }
5753 } else if (q) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005754 tmp64 = tcg_temp_new_i64();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005755 if (imm < 8) {
5756 neon_load_reg64(cpu_V0, rn);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005757 neon_load_reg64(tmp64, rn + 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005758 } else {
5759 neon_load_reg64(cpu_V0, rn + 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005760 neon_load_reg64(tmp64, rm);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005761 }
5762 tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005763 tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005764 tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
5765 if (imm < 8) {
5766 neon_load_reg64(cpu_V1, rm);
5767 } else {
5768 neon_load_reg64(cpu_V1, rm + 1);
5769 imm -= 8;
5770 }
5771 tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005772 tcg_gen_shri_i64(tmp64, tmp64, imm * 8);
5773 tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005774 tcg_temp_free_i64(tmp64);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005775 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005776 /* BUGFIX */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005777 neon_load_reg64(cpu_V0, rn);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005778 tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005779 neon_load_reg64(cpu_V1, rm);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07005780 tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005781 tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
5782 }
5783 neon_store_reg64(cpu_V0, rd);
5784 if (q) {
5785 neon_store_reg64(cpu_V1, rd + 1);
5786 }
5787 } else if ((insn & (1 << 11)) == 0) {
5788 /* Two register misc. */
5789 op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
5790 size = (insn >> 18) & 3;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005791 /* UNDEF for unknown op values and bad op-size combinations */
5792 if ((neon_2rm_sizes[op] & (1 << size)) == 0) {
5793 return 1;
5794 }
5795 if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&
5796 q && ((rm | rd) & 1)) {
5797 return 1;
5798 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005799 switch (op) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005800 case NEON_2RM_VREV64:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005801 for (pass = 0; pass < (q ? 2 : 1); pass++) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005802 tmp = neon_load_reg(rm, pass * 2);
5803 tmp2 = neon_load_reg(rm, pass * 2 + 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005804 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005805 case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
5806 case 1: gen_swap_half(tmp); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005807 case 2: /* no-op */ break;
5808 default: abort();
5809 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005810 neon_store_reg(rd, pass * 2 + 1, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005811 if (size == 2) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005812 neon_store_reg(rd, pass * 2, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005813 } else {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005814 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005815 case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break;
5816 case 1: gen_swap_half(tmp2); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005817 default: abort();
5818 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005819 neon_store_reg(rd, pass * 2, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005820 }
5821 }
5822 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005823 case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
5824 case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005825 for (pass = 0; pass < q + 1; pass++) {
5826 tmp = neon_load_reg(rm, pass * 2);
5827 gen_neon_widen(cpu_V0, tmp, size, op & 1);
5828 tmp = neon_load_reg(rm, pass * 2 + 1);
5829 gen_neon_widen(cpu_V1, tmp, size, op & 1);
5830 switch (size) {
5831 case 0: gen_helper_neon_paddl_u16(CPU_V001); break;
5832 case 1: gen_helper_neon_paddl_u32(CPU_V001); break;
5833 case 2: tcg_gen_add_i64(CPU_V001); break;
5834 default: abort();
5835 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02005836 if (op >= NEON_2RM_VPADAL) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005837 /* Accumulate. */
5838 neon_load_reg64(cpu_V1, rd + pass);
5839 gen_neon_addl(size);
5840 }
5841 neon_store_reg64(cpu_V0, rd + pass);
5842 }
5843 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005844 case NEON_2RM_VTRN:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005845 if (size == 2) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005846 int n;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005847 for (n = 0; n < (q ? 4 : 2); n += 2) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005848 tmp = neon_load_reg(rm, n);
5849 tmp2 = neon_load_reg(rd, n + 1);
5850 neon_store_reg(rm, n, tmp2);
5851 neon_store_reg(rd, n + 1, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005852 }
5853 } else {
5854 goto elementwise;
5855 }
5856 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005857 case NEON_2RM_VUZP:
5858 if (gen_neon_unzip(rd, rm, size, q)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005859 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005860 }
5861 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005862 case NEON_2RM_VZIP:
5863 if (gen_neon_zip(rd, rm, size, q)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005864 return 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005865 }
5866 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005867 case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
5868 /* also VQMOVUN; op field and mnemonics don't line up */
5869 if (rm & 1) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005870 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005871 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005872 TCGV_UNUSED(tmp2);
5873 for (pass = 0; pass < 2; pass++) {
5874 neon_load_reg64(cpu_V0, rm + pass);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005875 tmp = tcg_temp_new_i32();
5876 gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size,
5877 tmp, cpu_V0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005878 if (pass == 0) {
5879 tmp2 = tmp;
5880 } else {
5881 neon_store_reg(rd, 0, tmp2);
5882 neon_store_reg(rd, 1, tmp);
5883 }
5884 }
5885 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005886 case NEON_2RM_VSHLL:
5887 if (q || (rd & 1)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005888 return 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005889 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005890 tmp = neon_load_reg(rm, 0);
5891 tmp2 = neon_load_reg(rm, 1);
5892 for (pass = 0; pass < 2; pass++) {
5893 if (pass == 1)
5894 tmp = tmp2;
5895 gen_neon_widen(cpu_V0, tmp, size, 1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02005896 tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005897 neon_store_reg64(cpu_V0, rd + pass);
5898 }
5899 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005900 case NEON_2RM_VCVT_F16_F32:
5901 if (!arm_feature(env, ARM_FEATURE_VFP_FP16) ||
5902 q || (rm & 1)) {
5903 return 1;
5904 }
5905 tmp = tcg_temp_new_i32();
5906 tmp2 = tcg_temp_new_i32();
5907 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
5908 gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
5909 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
5910 gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
5911 tcg_gen_shli_i32(tmp2, tmp2, 16);
5912 tcg_gen_or_i32(tmp2, tmp2, tmp);
5913 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));
5914 gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
5915 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
5916 neon_store_reg(rd, 0, tmp2);
5917 tmp2 = tcg_temp_new_i32();
5918 gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
5919 tcg_gen_shli_i32(tmp2, tmp2, 16);
5920 tcg_gen_or_i32(tmp2, tmp2, tmp);
5921 neon_store_reg(rd, 1, tmp2);
5922 tcg_temp_free_i32(tmp);
5923 break;
5924 case NEON_2RM_VCVT_F32_F16:
5925 if (!arm_feature(env, ARM_FEATURE_VFP_FP16) ||
5926 q || (rd & 1)) {
5927 return 1;
5928 }
5929 tmp3 = tcg_temp_new_i32();
5930 tmp = neon_load_reg(rm, 0);
5931 tmp2 = neon_load_reg(rm, 1);
5932 tcg_gen_ext16u_i32(tmp3, tmp);
5933 gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
5934 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
5935 tcg_gen_shri_i32(tmp3, tmp, 16);
5936 gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
5937 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
5938 tcg_temp_free_i32(tmp);
5939 tcg_gen_ext16u_i32(tmp3, tmp2);
5940 gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
5941 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
5942 tcg_gen_shri_i32(tmp3, tmp2, 16);
5943 gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
5944 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
5945 tcg_temp_free_i32(tmp2);
5946 tcg_temp_free_i32(tmp3);
5947 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005948 default:
5949 elementwise:
5950 for (pass = 0; pass < (q ? 4 : 2); pass++) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005951 if (neon_2rm_is_float_op(op)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005952 tcg_gen_ld_f32(cpu_F0s, cpu_env,
5953 neon_reg_offset(rm, pass));
David 'Digit' Turner52858642011-06-03 13:41:05 +02005954 TCGV_UNUSED(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005955 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005956 tmp = neon_load_reg(rm, pass);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005957 }
5958 switch (op) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005959 case NEON_2RM_VREV32:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005960 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005961 case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
5962 case 1: gen_swap_half(tmp); break;
5963 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005964 }
5965 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005966 case NEON_2RM_VREV16:
5967 gen_rev16(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005968 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005969 case NEON_2RM_VCLS:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005970 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005971 case 0: gen_helper_neon_cls_s8(tmp, tmp); break;
5972 case 1: gen_helper_neon_cls_s16(tmp, tmp); break;
5973 case 2: gen_helper_neon_cls_s32(tmp, tmp); break;
5974 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005975 }
5976 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005977 case NEON_2RM_VCLZ:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005978 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02005979 case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
5980 case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
5981 case 2: gen_helper_clz(tmp, tmp); break;
5982 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005983 }
5984 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005985 case NEON_2RM_VCNT:
5986 gen_helper_neon_cnt_u8(tmp, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005987 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005988 case NEON_2RM_VMVN:
5989 tcg_gen_not_i32(tmp, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005990 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02005991 case NEON_2RM_VQABS:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005992 switch (size) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01005993 case 0:
5994 gen_helper_neon_qabs_s8(tmp, cpu_env, tmp);
5995 break;
5996 case 1:
5997 gen_helper_neon_qabs_s16(tmp, cpu_env, tmp);
5998 break;
5999 case 2:
6000 gen_helper_neon_qabs_s32(tmp, cpu_env, tmp);
6001 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006002 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006003 }
6004 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006005 case NEON_2RM_VQNEG:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006006 switch (size) {
David 'Digit' Turner3d323dd2014-03-19 10:42:06 +01006007 case 0:
6008 gen_helper_neon_qneg_s8(tmp, cpu_env, tmp);
6009 break;
6010 case 1:
6011 gen_helper_neon_qneg_s16(tmp, cpu_env, tmp);
6012 break;
6013 case 2:
6014 gen_helper_neon_qneg_s32(tmp, cpu_env, tmp);
6015 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006016 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006017 }
6018 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006019 case NEON_2RM_VCGT0: case NEON_2RM_VCLE0:
6020 tmp2 = tcg_const_i32(0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006021 switch(size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006022 case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break;
6023 case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break;
6024 case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break;
6025 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006026 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006027 tcg_temp_free(tmp2);
6028 if (op == NEON_2RM_VCLE0) {
6029 tcg_gen_not_i32(tmp, tmp);
6030 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006031 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006032 case NEON_2RM_VCGE0: case NEON_2RM_VCLT0:
6033 tmp2 = tcg_const_i32(0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006034 switch(size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006035 case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break;
6036 case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break;
6037 case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break;
6038 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006039 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006040 tcg_temp_free(tmp2);
6041 if (op == NEON_2RM_VCLT0) {
6042 tcg_gen_not_i32(tmp, tmp);
6043 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006044 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006045 case NEON_2RM_VCEQ0:
6046 tmp2 = tcg_const_i32(0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006047 switch(size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006048 case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
6049 case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
6050 case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
6051 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006052 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006053 tcg_temp_free(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006054 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006055 case NEON_2RM_VABS:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006056 switch(size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006057 case 0: gen_helper_neon_abs_s8(tmp, tmp); break;
6058 case 1: gen_helper_neon_abs_s16(tmp, tmp); break;
6059 case 2: tcg_gen_abs_i32(tmp, tmp); break;
6060 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006061 }
6062 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006063 case NEON_2RM_VNEG:
6064 tmp2 = tcg_const_i32(0);
6065 gen_neon_rsb(size, tmp, tmp2);
6066 tcg_temp_free(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006067 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006068 case NEON_2RM_VCGT0_F:
David 'Digit' Turner16998982014-03-18 17:23:07 +01006069 {
6070 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006071 tmp2 = tcg_const_i32(0);
David 'Digit' Turner16998982014-03-18 17:23:07 +01006072 gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006073 tcg_temp_free(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006074 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01006075 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006076 case NEON_2RM_VCGE0_F:
David 'Digit' Turner16998982014-03-18 17:23:07 +01006077 {
6078 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006079 tmp2 = tcg_const_i32(0);
David 'Digit' Turner16998982014-03-18 17:23:07 +01006080 gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006081 tcg_temp_free(tmp2);
David 'Digit' Turner16998982014-03-18 17:23:07 +01006082 tcg_temp_free_ptr(fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006083 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01006084 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006085 case NEON_2RM_VCEQ0_F:
David 'Digit' Turner16998982014-03-18 17:23:07 +01006086 {
6087 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006088 tmp2 = tcg_const_i32(0);
David 'Digit' Turner16998982014-03-18 17:23:07 +01006089 gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006090 tcg_temp_free(tmp2);
David 'Digit' Turner16998982014-03-18 17:23:07 +01006091 tcg_temp_free_ptr(fpstatus);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006092 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01006093 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006094 case NEON_2RM_VCLE0_F:
David 'Digit' Turner16998982014-03-18 17:23:07 +01006095 {
6096 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006097 tmp2 = tcg_const_i32(0);
David 'Digit' Turner16998982014-03-18 17:23:07 +01006098 gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006099 tcg_temp_free(tmp2);
David 'Digit' Turner16998982014-03-18 17:23:07 +01006100 tcg_temp_free_ptr(fpstatus);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006101 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01006102 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006103 case NEON_2RM_VCLT0_F:
David 'Digit' Turner16998982014-03-18 17:23:07 +01006104 {
6105 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006106 tmp2 = tcg_const_i32(0);
David 'Digit' Turner16998982014-03-18 17:23:07 +01006107 gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006108 tcg_temp_free(tmp2);
David 'Digit' Turner16998982014-03-18 17:23:07 +01006109 tcg_temp_free_ptr(fpstatus);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006110 break;
David 'Digit' Turner16998982014-03-18 17:23:07 +01006111 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006112 case NEON_2RM_VABS_F:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006113 gen_vfp_abs(0);
6114 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006115 case NEON_2RM_VNEG_F:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006116 gen_vfp_neg(0);
6117 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006118 case NEON_2RM_VSWP:
6119 tmp2 = neon_load_reg(rd, pass);
6120 neon_store_reg(rm, pass, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006121 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006122 case NEON_2RM_VTRN:
6123 tmp2 = neon_load_reg(rd, pass);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006124 switch (size) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006125 case 0: gen_neon_trn_u8(tmp, tmp2); break;
6126 case 1: gen_neon_trn_u16(tmp, tmp2); break;
6127 default: abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006128 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006129 neon_store_reg(rm, pass, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006130 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006131 case NEON_2RM_VRECPE:
6132 gen_helper_recpe_u32(tmp, tmp, cpu_env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006133 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006134 case NEON_2RM_VRSQRTE:
6135 gen_helper_rsqrte_u32(tmp, tmp, cpu_env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006136 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006137 case NEON_2RM_VRECPE_F:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006138 gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env);
6139 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006140 case NEON_2RM_VRSQRTE_F:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006141 gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
6142 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006143 case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
6144 gen_vfp_sito(0, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006145 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006146 case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */
6147 gen_vfp_uito(0, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006148 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006149 case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */
6150 gen_vfp_tosiz(0, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006151 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006152 case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */
6153 gen_vfp_touiz(0, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006154 break;
6155 default:
David 'Digit' Turner52858642011-06-03 13:41:05 +02006156 /* Reserved op values were caught by the
6157 * neon_2rm_sizes[] check earlier.
6158 */
6159 abort();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006160 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006161 if (neon_2rm_is_float_op(op)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006162 tcg_gen_st_f32(cpu_F0s, cpu_env,
6163 neon_reg_offset(rd, pass));
6164 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006165 neon_store_reg(rd, pass, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006166 }
6167 }
6168 break;
6169 }
6170 } else if ((insn & (1 << 10)) == 0) {
6171 /* VTBL, VTBX. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006172 int n = ((insn >> 8) & 3) + 1;
6173 if ((rn + n) > 32) {
6174 /* This is UNPREDICTABLE; we choose to UNDEF to avoid the
6175 * helper function running off the end of the register file.
6176 */
6177 return 1;
6178 }
6179 n <<= 3;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006180 if (insn & (1 << 6)) {
6181 tmp = neon_load_reg(rd, 0);
6182 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006183 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006184 tcg_gen_movi_i32(tmp, 0);
6185 }
6186 tmp2 = neon_load_reg(rm, 0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006187 tmp4 = tcg_const_i32(rn);
6188 tmp5 = tcg_const_i32(n);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02006189 gen_helper_neon_tbl(tmp2, cpu_env, tmp2, tmp, tmp4, tmp5);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006190 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006191 if (insn & (1 << 6)) {
6192 tmp = neon_load_reg(rd, 1);
6193 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006194 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006195 tcg_gen_movi_i32(tmp, 0);
6196 }
6197 tmp3 = neon_load_reg(rm, 1);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02006198 gen_helper_neon_tbl(tmp3, cpu_env, tmp3, tmp, tmp4, tmp5);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006199 tcg_temp_free_i32(tmp5);
6200 tcg_temp_free_i32(tmp4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006201 neon_store_reg(rd, 0, tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006202 neon_store_reg(rd, 1, tmp3);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006203 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006204 } else if ((insn & 0x380) == 0) {
6205 /* VDUP */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006206 if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {
6207 return 1;
6208 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006209 if (insn & (1 << 19)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006210 tmp = neon_load_reg(rm, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006211 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006212 tmp = neon_load_reg(rm, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006213 }
6214 if (insn & (1 << 16)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006215 gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006216 } else if (insn & (1 << 17)) {
6217 if ((insn >> 18) & 1)
David 'Digit' Turner52858642011-06-03 13:41:05 +02006218 gen_neon_dup_high16(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006219 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02006220 gen_neon_dup_low16(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006221 }
6222 for (pass = 0; pass < (q ? 4 : 2); pass++) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006223 tmp2 = tcg_temp_new_i32();
6224 tcg_gen_mov_i32(tmp2, tmp);
6225 neon_store_reg(rd, pass, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006226 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006227 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006228 } else {
6229 return 1;
6230 }
6231 }
6232 }
6233 return 0;
6234}
6235
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01006236static int disas_cp14_read(CPUARMState * env, DisasContext *s, uint32_t insn)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006237{
6238 int crn = (insn >> 16) & 0xf;
6239 int crm = insn & 0xf;
6240 int op1 = (insn >> 21) & 7;
6241 int op2 = (insn >> 5) & 7;
6242 int rt = (insn >> 12) & 0xf;
6243 TCGv tmp;
6244
David 'Digit' Turner52858642011-06-03 13:41:05 +02006245 /* Minimal set of debug registers, since we don't support debug */
6246 if (op1 == 0 && crn == 0 && op2 == 0) {
6247 switch (crm) {
6248 case 0:
6249 /* DBGDIDR: just RAZ. In particular this means the
6250 * "debug architecture version" bits will read as
6251 * a reserved value, which should cause Linux to
6252 * not try to use the debug hardware.
6253 */
6254 tmp = tcg_const_i32(0);
6255 store_reg(s, rt, tmp);
6256 return 0;
6257 case 1:
6258 case 2:
6259 /* DBGDRAR and DBGDSAR: v7 only. Always RAZ since we
6260 * don't implement memory mapped debug components
6261 */
6262 if (ENABLE_ARCH_7) {
6263 tmp = tcg_const_i32(0);
6264 store_reg(s, rt, tmp);
6265 return 0;
6266 }
6267 break;
6268 default:
6269 break;
6270 }
6271 }
6272
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006273 if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
6274 if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
6275 /* TEECR */
6276 if (IS_USER(s))
6277 return 1;
6278 tmp = load_cpu_field(teecr);
6279 store_reg(s, rt, tmp);
6280 return 0;
6281 }
6282 if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
6283 /* TEEHBR */
6284 if (IS_USER(s) && (env->teecr & 1))
6285 return 1;
6286 tmp = load_cpu_field(teehbr);
6287 store_reg(s, rt, tmp);
6288 return 0;
6289 }
6290 }
6291 fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n",
6292 op1, crn, crm, op2);
6293 return 1;
6294}
6295
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01006296static int disas_cp14_write(CPUARMState * env, DisasContext *s, uint32_t insn)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006297{
6298 int crn = (insn >> 16) & 0xf;
6299 int crm = insn & 0xf;
6300 int op1 = (insn >> 21) & 7;
6301 int op2 = (insn >> 5) & 7;
6302 int rt = (insn >> 12) & 0xf;
6303 TCGv tmp;
6304
David 'Digit' Turner52858642011-06-03 13:41:05 +02006305 /* Minimal set of debug registers, since we don't support debug */
6306 if (op1 == 0 && crn == 0 && op2 == 0) {
6307 switch (crm) {
6308 case 0:
6309 /* DBGDIDR */
6310 tmp = load_cpu_field(cp14_dbgdidr);
6311 store_reg(s, rt, tmp);
6312 return 0;
6313 case 1:
6314 case 2:
6315 /* DBGDRAR and DBGDSAR: v7 only. Always RAZ since we
6316 * don't implement memory mapped debug components
6317 */
6318 if (ENABLE_ARCH_7) {
6319 tmp = tcg_const_i32(0);
6320 store_reg(s, rt, tmp);
6321 return 0;
6322 }
6323 break;
6324 default:
6325 break;
6326 }
6327 }
6328
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006329 if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
6330 if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
6331 /* TEECR */
6332 if (IS_USER(s))
6333 return 1;
6334 tmp = load_reg(s, rt);
6335 gen_helper_set_teecr(cpu_env, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006336 tcg_temp_free_i32(tmp);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006337 return 0;
6338 }
6339 if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
6340 /* TEEHBR */
6341 if (IS_USER(s) && (env->teecr & 1))
6342 return 1;
6343 tmp = load_reg(s, rt);
6344 store_cpu_field(tmp, teehbr);
6345 return 0;
6346 }
6347 }
6348 fprintf(stderr, "Unknown cp14 write op1:%d crn:%d crm:%d op2:%d\n",
6349 op1, crn, crm, op2);
6350 return 1;
6351}
6352
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01006353static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006354{
6355 int cpnum;
6356
6357 cpnum = (insn >> 8) & 0xf;
6358 if (arm_feature(env, ARM_FEATURE_XSCALE)
6359 && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
6360 return 1;
6361
6362 switch (cpnum) {
6363 case 0:
6364 case 1:
6365 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
6366 return disas_iwmmxt_insn(env, s, insn);
6367 } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
6368 return disas_dsp_insn(env, s, insn);
6369 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006370 goto board;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006371 case 10:
6372 case 11:
6373 return disas_vfp_insn (env, s, insn);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006374 case 14:
6375 /* Coprocessors 7-15 are architecturally reserved by ARM.
6376 Unfortunately Intel decided to ignore this. */
6377 if (arm_feature(env, ARM_FEATURE_XSCALE))
6378 goto board;
6379 if (insn & (1 << 20))
6380 return disas_cp14_read(env, s, insn);
6381 else
6382 return disas_cp14_write(env, s, insn);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006383 case 15:
6384 return disas_cp15_insn (env, s, insn);
6385 default:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006386 board:
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006387 /* Unknown coprocessor. See if the board has hooked it. */
6388 return disas_cp_insn (env, s, insn);
6389 }
6390}
6391
6392
6393/* Store a 64-bit value to a register pair. Clobbers val. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006394static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006395{
6396 TCGv tmp;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006397 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006398 tcg_gen_trunc_i64_i32(tmp, val);
6399 store_reg(s, rlow, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006400 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006401 tcg_gen_shri_i64(val, val, 32);
6402 tcg_gen_trunc_i64_i32(tmp, val);
6403 store_reg(s, rhigh, tmp);
6404}
6405
6406/* load a 32-bit value from a register and perform a 64-bit accumulate. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006407static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006408{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006409 TCGv_i64 tmp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006410 TCGv tmp2;
6411
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006412 /* Load value and extend to 64 bits. */
6413 tmp = tcg_temp_new_i64();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006414 tmp2 = load_reg(s, rlow);
6415 tcg_gen_extu_i32_i64(tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006416 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006417 tcg_gen_add_i64(val, val, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006418 tcg_temp_free_i64(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006419}
6420
6421/* load and add a 64-bit value from a register pair. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006422static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006423{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006424 TCGv_i64 tmp;
6425 TCGv tmpl;
6426 TCGv tmph;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006427
6428 /* Load 64-bit value rd:rn. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006429 tmpl = load_reg(s, rlow);
6430 tmph = load_reg(s, rhigh);
6431 tmp = tcg_temp_new_i64();
6432 tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006433 tcg_temp_free_i32(tmpl);
6434 tcg_temp_free_i32(tmph);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006435 tcg_gen_add_i64(val, val, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006436 tcg_temp_free_i64(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006437}
6438
6439/* Set N and Z flags from a 64-bit value. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006440static void gen_logicq_cc(TCGv_i64 val)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006441{
David 'Digit' Turner52858642011-06-03 13:41:05 +02006442 TCGv tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006443 gen_helper_logicq_cc(tmp, val);
6444 gen_logic_CC(tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006445 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006446}
6447
David 'Digit' Turner52858642011-06-03 13:41:05 +02006448/* Load/Store exclusive instructions are implemented by remembering
6449 the value/address loaded, and seeing if these are the same
6450 when the store is performed. This should be is sufficient to implement
6451 the architecturally mandated semantics, and avoids having to monitor
6452 regular stores.
6453
6454 In system emulation mode only one CPU will be running at once, so
6455 this sequence is effectively atomic. In user emulation mode we
6456 throw an exception and handle the atomic operation elsewhere. */
6457static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
6458 TCGv addr, int size)
6459{
6460 TCGv tmp;
6461
6462 switch (size) {
6463 case 0:
6464 tmp = gen_ld8u(addr, IS_USER(s));
6465 break;
6466 case 1:
6467 tmp = gen_ld16u(addr, IS_USER(s));
6468 break;
6469 case 2:
6470 case 3:
6471 tmp = gen_ld32(addr, IS_USER(s));
6472 break;
6473 default:
6474 abort();
6475 }
6476 tcg_gen_mov_i32(cpu_exclusive_val, tmp);
6477 store_reg(s, rt, tmp);
6478 if (size == 3) {
6479 TCGv tmp2 = tcg_temp_new_i32();
6480 tcg_gen_addi_i32(tmp2, addr, 4);
6481 tmp = gen_ld32(tmp2, IS_USER(s));
6482 tcg_temp_free_i32(tmp2);
6483 tcg_gen_mov_i32(cpu_exclusive_high, tmp);
6484 store_reg(s, rt2, tmp);
6485 }
6486 tcg_gen_mov_i32(cpu_exclusive_addr, addr);
6487}
6488
6489static void gen_clrex(DisasContext *s)
6490{
6491 tcg_gen_movi_i32(cpu_exclusive_addr, -1);
6492}
6493
6494#ifdef CONFIG_USER_ONLY
6495static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
6496 TCGv addr, int size)
6497{
6498 tcg_gen_mov_i32(cpu_exclusive_test, addr);
6499 tcg_gen_movi_i32(cpu_exclusive_info,
6500 size | (rd << 4) | (rt << 8) | (rt2 << 12));
6501 gen_exception_insn(s, 4, EXCP_STREX);
6502}
6503#else
6504static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
6505 TCGv addr, int size)
6506{
6507 TCGv tmp;
6508 int done_label;
6509 int fail_label;
6510
6511 /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) {
6512 [addr] = {Rt};
6513 {Rd} = 0;
6514 } else {
6515 {Rd} = 1;
6516 } */
6517 fail_label = gen_new_label();
6518 done_label = gen_new_label();
6519 tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
6520 switch (size) {
6521 case 0:
6522 tmp = gen_ld8u(addr, IS_USER(s));
6523 break;
6524 case 1:
6525 tmp = gen_ld16u(addr, IS_USER(s));
6526 break;
6527 case 2:
6528 case 3:
6529 tmp = gen_ld32(addr, IS_USER(s));
6530 break;
6531 default:
6532 abort();
6533 }
6534 tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
6535 tcg_temp_free_i32(tmp);
6536 if (size == 3) {
6537 TCGv tmp2 = tcg_temp_new_i32();
6538 tcg_gen_addi_i32(tmp2, addr, 4);
6539 tmp = gen_ld32(tmp2, IS_USER(s));
6540 tcg_temp_free_i32(tmp2);
6541 tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
6542 tcg_temp_free_i32(tmp);
6543 }
6544 tmp = load_reg(s, rt);
6545 switch (size) {
6546 case 0:
6547 gen_st8(tmp, addr, IS_USER(s));
6548 break;
6549 case 1:
6550 gen_st16(tmp, addr, IS_USER(s));
6551 break;
6552 case 2:
6553 case 3:
6554 gen_st32(tmp, addr, IS_USER(s));
6555 break;
6556 default:
6557 abort();
6558 }
6559 if (size == 3) {
6560 tcg_gen_addi_i32(addr, addr, 4);
6561 tmp = load_reg(s, rt2);
6562 gen_st32(tmp, addr, IS_USER(s));
6563 }
6564 tcg_gen_movi_i32(cpu_R[rd], 0);
6565 tcg_gen_br(done_label);
6566 gen_set_label(fail_label);
6567 tcg_gen_movi_i32(cpu_R[rd], 1);
6568 gen_set_label(done_label);
6569 tcg_gen_movi_i32(cpu_exclusive_addr, -1);
6570}
6571#endif
David 'Digit' Turnera577fca2009-10-15 18:18:09 -07006572
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01006573static void disas_arm_insn(CPUARMState * env, DisasContext *s)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006574{
6575 unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
6576 TCGv tmp;
6577 TCGv tmp2;
6578 TCGv tmp3;
6579 TCGv addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006580 TCGv_i64 tmp64;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006581
David 'Digit' Turnereca7bc22014-03-14 23:58:39 +01006582 insn = cpu_ldl_code(env, s->pc);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08006583
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006584 s->pc += 4;
6585
6586 /* M variants do not implement ARM mode. */
6587 if (IS_M(env))
6588 goto illegal_op;
6589 cond = insn >> 28;
6590 if (cond == 0xf){
David 'Digit' Turner52858642011-06-03 13:41:05 +02006591 /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we
6592 * choose to UNDEF. In ARMv5 and above the space is used
6593 * for miscellaneous unconditional instructions.
6594 */
6595 ARCH(5);
6596
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006597 /* Unconditional instructions. */
6598 if (((insn >> 25) & 7) == 1) {
6599 /* NEON Data processing. */
6600 if (!arm_feature(env, ARM_FEATURE_NEON))
6601 goto illegal_op;
6602
6603 if (disas_neon_data_insn(env, s, insn))
6604 goto illegal_op;
6605 return;
6606 }
6607 if ((insn & 0x0f100000) == 0x04000000) {
6608 /* NEON load/store. */
6609 if (!arm_feature(env, ARM_FEATURE_NEON))
6610 goto illegal_op;
6611
6612 if (disas_neon_ls_insn(env, s, insn))
6613 goto illegal_op;
6614 return;
6615 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006616 if (((insn & 0x0f30f000) == 0x0510f000) ||
6617 ((insn & 0x0f30f010) == 0x0710f000)) {
6618 if ((insn & (1 << 22)) == 0) {
6619 /* PLDW; v7MP */
6620 if (!arm_feature(env, ARM_FEATURE_V7MP)) {
6621 goto illegal_op;
6622 }
6623 }
6624 /* Otherwise PLD; v5TE+ */
6625 ARCH(5TE);
6626 return;
6627 }
6628 if (((insn & 0x0f70f000) == 0x0450f000) ||
6629 ((insn & 0x0f70f010) == 0x0650f000)) {
6630 ARCH(7);
6631 return; /* PLI; V7 */
6632 }
6633 if (((insn & 0x0f700000) == 0x04100000) ||
6634 ((insn & 0x0f700010) == 0x06100000)) {
6635 if (!arm_feature(env, ARM_FEATURE_V7MP)) {
6636 goto illegal_op;
6637 }
6638 return; /* v7MP: Unallocated memory hint: must NOP */
6639 }
6640
6641 if ((insn & 0x0ffffdff) == 0x01010000) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006642 ARCH(6);
6643 /* setend */
6644 if (insn & (1 << 9)) {
6645 /* BE8 mode not implemented. */
6646 goto illegal_op;
6647 }
6648 return;
6649 } else if ((insn & 0x0fffff00) == 0x057ff000) {
6650 switch ((insn >> 4) & 0xf) {
6651 case 1: /* clrex */
6652 ARCH(6K);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006653 gen_clrex(s);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006654 return;
6655 case 4: /* dsb */
6656 case 5: /* dmb */
6657 case 6: /* isb */
6658 ARCH(7);
6659 /* We don't emulate caches so these are a no-op. */
6660 return;
6661 default:
6662 goto illegal_op;
6663 }
6664 } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
6665 /* srs */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006666 int32_t offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006667 if (IS_USER(s))
6668 goto illegal_op;
6669 ARCH(6);
6670 op1 = (insn & 0x1f);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006671 addr = tcg_temp_new_i32();
6672 tmp = tcg_const_i32(op1);
6673 gen_helper_get_r13_banked(addr, cpu_env, tmp);
6674 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006675 i = (insn >> 23) & 3;
6676 switch (i) {
6677 case 0: offset = -4; break; /* DA */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006678 case 1: offset = 0; break; /* IA */
6679 case 2: offset = -8; break; /* DB */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006680 case 3: offset = 4; break; /* IB */
6681 default: abort();
6682 }
6683 if (offset)
6684 tcg_gen_addi_i32(addr, addr, offset);
6685 tmp = load_reg(s, 14);
6686 gen_st32(tmp, addr, 0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006687 tmp = load_cpu_field(spsr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006688 tcg_gen_addi_i32(addr, addr, 4);
6689 gen_st32(tmp, addr, 0);
6690 if (insn & (1 << 21)) {
6691 /* Base writeback. */
6692 switch (i) {
6693 case 0: offset = -8; break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006694 case 1: offset = 4; break;
6695 case 2: offset = -4; break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006696 case 3: offset = 0; break;
6697 default: abort();
6698 }
6699 if (offset)
David 'Digit' Turner52858642011-06-03 13:41:05 +02006700 tcg_gen_addi_i32(addr, addr, offset);
6701 tmp = tcg_const_i32(op1);
6702 gen_helper_set_r13_banked(cpu_env, tmp, addr);
6703 tcg_temp_free_i32(tmp);
6704 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006705 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006706 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006707 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02006708 return;
6709 } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006710 /* rfe */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006711 int32_t offset;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006712 if (IS_USER(s))
6713 goto illegal_op;
6714 ARCH(6);
6715 rn = (insn >> 16) & 0xf;
6716 addr = load_reg(s, rn);
6717 i = (insn >> 23) & 3;
6718 switch (i) {
6719 case 0: offset = -4; break; /* DA */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006720 case 1: offset = 0; break; /* IA */
6721 case 2: offset = -8; break; /* DB */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006722 case 3: offset = 4; break; /* IB */
6723 default: abort();
6724 }
6725 if (offset)
6726 tcg_gen_addi_i32(addr, addr, offset);
6727 /* Load PC into tmp and CPSR into tmp2. */
6728 tmp = gen_ld32(addr, 0);
6729 tcg_gen_addi_i32(addr, addr, 4);
6730 tmp2 = gen_ld32(addr, 0);
6731 if (insn & (1 << 21)) {
6732 /* Base writeback. */
6733 switch (i) {
6734 case 0: offset = -8; break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006735 case 1: offset = 4; break;
6736 case 2: offset = -4; break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006737 case 3: offset = 0; break;
6738 default: abort();
6739 }
6740 if (offset)
6741 tcg_gen_addi_i32(addr, addr, offset);
6742 store_reg(s, rn, addr);
6743 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006744 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006745 }
6746 gen_rfe(s, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006747 return;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006748 } else if ((insn & 0x0e000000) == 0x0a000000) {
6749 /* branch link and change to thumb (blx <offset>) */
6750 int32_t offset;
6751
6752 val = (uint32_t)s->pc;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006753 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006754 tcg_gen_movi_i32(tmp, val);
6755 store_reg(s, 14, tmp);
6756 /* Sign-extend the 24-bit offset */
6757 offset = (((int32_t)insn) << 8) >> 8;
6758 /* offset * 4 + bit24 * 2 + (thumb bit) */
6759 val += (offset << 2) | ((insn >> 23) & 2) | 1;
6760 /* pipeline offset */
6761 val += 4;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006762 /* protected by ARCH(5); above, near the start of uncond block */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006763 gen_bx_im(s, val);
6764 return;
6765 } else if ((insn & 0x0e000f00) == 0x0c000100) {
6766 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
6767 /* iWMMXt register transfer. */
6768 if (env->cp15.c15_cpar & (1 << 1))
6769 if (!disas_iwmmxt_insn(env, s, insn))
6770 return;
6771 }
6772 } else if ((insn & 0x0fe00000) == 0x0c400000) {
6773 /* Coprocessor double register transfer. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006774 ARCH(5TE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006775 } else if ((insn & 0x0f000010) == 0x0e000010) {
6776 /* Additional coprocessor register transfer. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006777 if (!disas_coproc_insn(env, s, insn)) {
6778 return;
6779 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006780 } else if ((insn & 0x0ff10020) == 0x01000000) {
6781 uint32_t mask;
6782 uint32_t val;
6783 /* cps (privileged) */
6784 if (IS_USER(s))
6785 return;
6786 mask = val = 0;
6787 if (insn & (1 << 19)) {
6788 if (insn & (1 << 8))
6789 mask |= CPSR_A;
6790 if (insn & (1 << 7))
6791 mask |= CPSR_I;
6792 if (insn & (1 << 6))
6793 mask |= CPSR_F;
6794 if (insn & (1 << 18))
6795 val |= mask;
6796 }
6797 if (insn & (1 << 17)) {
6798 mask |= CPSR_M;
6799 val |= (insn & 0x1f);
6800 }
6801 if (mask) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006802 gen_set_psr_im(s, mask, 0, val);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006803 }
6804 return;
6805 }
6806 goto illegal_op;
6807 }
6808 if (cond != 0xe) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006809 /* if not always execute, we generate a conditional jump to
6810 next instruction */
6811 s->condlabel = gen_new_label();
6812 gen_test_cc(cond ^ 1, s->condlabel);
6813 s->condjmp = 1;
6814 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006815 if ((insn & 0x0f900000) == 0x03000000) {
6816 if ((insn & (1 << 21)) == 0) {
6817 ARCH(6T2);
6818 rd = (insn >> 12) & 0xf;
6819 val = ((insn >> 4) & 0xf000) | (insn & 0xfff);
6820 if ((insn & (1 << 22)) == 0) {
6821 /* MOVW */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006822 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006823 tcg_gen_movi_i32(tmp, val);
6824 } else {
6825 /* MOVT */
6826 tmp = load_reg(s, rd);
6827 tcg_gen_ext16u_i32(tmp, tmp);
6828 tcg_gen_ori_i32(tmp, tmp, val << 16);
6829 }
6830 store_reg(s, rd, tmp);
6831 } else {
6832 if (((insn >> 12) & 0xf) != 0xf)
6833 goto illegal_op;
6834 if (((insn >> 16) & 0xf) == 0) {
6835 gen_nop_hint(s, insn & 0xff);
6836 } else {
6837 /* CPSR = immediate */
6838 val = insn & 0xff;
6839 shift = ((insn >> 8) & 0xf) * 2;
6840 if (shift)
6841 val = (val >> shift) | (val << (32 - shift));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006842 i = ((insn & (1 << 22)) != 0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006843 if (gen_set_psr_im(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, val))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006844 goto illegal_op;
6845 }
6846 }
6847 } else if ((insn & 0x0f900000) == 0x01000000
6848 && (insn & 0x00000090) != 0x00000090) {
6849 /* miscellaneous instructions */
6850 op1 = (insn >> 21) & 3;
6851 sh = (insn >> 4) & 0xf;
6852 rm = insn & 0xf;
6853 switch (sh) {
6854 case 0x0: /* move program status register */
6855 if (op1 & 1) {
6856 /* PSR = reg */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006857 tmp = load_reg(s, rm);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006858 i = ((op1 & 2) != 0);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006859 if (gen_set_psr(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, tmp))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006860 goto illegal_op;
6861 } else {
6862 /* reg = PSR */
6863 rd = (insn >> 12) & 0xf;
6864 if (op1 & 2) {
6865 if (IS_USER(s))
6866 goto illegal_op;
6867 tmp = load_cpu_field(spsr);
6868 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02006869 tmp = tcg_temp_new_i32();
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02006870 gen_helper_cpsr_read(tmp, cpu_env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006871 }
6872 store_reg(s, rd, tmp);
6873 }
6874 break;
6875 case 0x1:
6876 if (op1 == 1) {
6877 /* branch/exchange thumb (bx). */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006878 ARCH(4T);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006879 tmp = load_reg(s, rm);
6880 gen_bx(s, tmp);
6881 } else if (op1 == 3) {
6882 /* clz */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006883 ARCH(5);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006884 rd = (insn >> 12) & 0xf;
6885 tmp = load_reg(s, rm);
6886 gen_helper_clz(tmp, tmp);
6887 store_reg(s, rd, tmp);
6888 } else {
6889 goto illegal_op;
6890 }
6891 break;
6892 case 0x2:
6893 if (op1 == 1) {
6894 ARCH(5J); /* bxj */
6895 /* Trivial implementation equivalent to bx. */
6896 tmp = load_reg(s, rm);
6897 gen_bx(s, tmp);
6898 } else {
6899 goto illegal_op;
6900 }
6901 break;
6902 case 0x3:
6903 if (op1 != 1)
6904 goto illegal_op;
6905
David 'Digit' Turner52858642011-06-03 13:41:05 +02006906 ARCH(5);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006907 /* branch link/exchange thumb (blx) */
6908 tmp = load_reg(s, rm);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006909 tmp2 = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006910 tcg_gen_movi_i32(tmp2, s->pc);
6911 store_reg(s, 14, tmp2);
6912 gen_bx(s, tmp);
6913 break;
6914 case 0x5: /* saturating add/subtract */
David 'Digit' Turner52858642011-06-03 13:41:05 +02006915 ARCH(5TE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006916 rd = (insn >> 12) & 0xf;
6917 rn = (insn >> 16) & 0xf;
David 'Digit' Turner80562522009-05-20 11:58:50 +02006918 tmp = load_reg(s, rm);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006919 tmp2 = load_reg(s, rn);
6920 if (op1 & 2)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02006921 gen_helper_double_saturate(tmp2, cpu_env, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006922 if (op1 & 1)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02006923 gen_helper_sub_saturate(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006924 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02006925 gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006926 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006927 store_reg(s, rd, tmp);
6928 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02006929 case 7:
6930 if (op1 == 1) {
6931 /* bkpt */
6932 ARCH(5);
6933 gen_exception_insn(s, 4, EXCP_BKPT);
6934 } else if (op1 == 3) {
6935 /* smi/smc */
6936 if (!(env->cp15.c0_c2[4] & 0xf000) || IS_USER(s)) {
6937 goto illegal_op;
6938 }
6939 gen_smc(env, s);
6940 } else {
6941 goto illegal_op;
6942 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006943 break;
6944 case 0x8: /* signed multiply */
6945 case 0xa:
6946 case 0xc:
6947 case 0xe:
David 'Digit' Turner52858642011-06-03 13:41:05 +02006948 ARCH(5TE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006949 rs = (insn >> 8) & 0xf;
6950 rn = (insn >> 12) & 0xf;
6951 rd = (insn >> 16) & 0xf;
6952 if (op1 == 1) {
6953 /* (32 * 16) >> 16 */
6954 tmp = load_reg(s, rm);
6955 tmp2 = load_reg(s, rs);
6956 if (sh & 4)
6957 tcg_gen_sari_i32(tmp2, tmp2, 16);
6958 else
6959 gen_sxth(tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006960 tmp64 = gen_muls_i64_i32(tmp, tmp2);
6961 tcg_gen_shri_i64(tmp64, tmp64, 16);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006962 tmp = tcg_temp_new_i32();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006963 tcg_gen_trunc_i64_i32(tmp, tmp64);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006964 tcg_temp_free_i64(tmp64);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006965 if ((sh & 2) == 0) {
6966 tmp2 = load_reg(s, rn);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02006967 gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006968 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006969 }
6970 store_reg(s, rd, tmp);
6971 } else {
6972 /* 16 * 16 */
6973 tmp = load_reg(s, rm);
6974 tmp2 = load_reg(s, rs);
6975 gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006976 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006977 if (op1 == 2) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006978 tmp64 = tcg_temp_new_i64();
6979 tcg_gen_ext_i32_i64(tmp64, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006980 tcg_temp_free_i32(tmp);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07006981 gen_addq(s, tmp64, rn, rd);
6982 gen_storeq_reg(s, rn, rd, tmp64);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006983 tcg_temp_free_i64(tmp64);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006984 } else {
6985 if (op1 == 0) {
6986 tmp2 = load_reg(s, rn);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02006987 gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02006988 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08006989 }
6990 store_reg(s, rd, tmp);
6991 }
6992 }
6993 break;
6994 default:
6995 goto illegal_op;
6996 }
6997 } else if (((insn & 0x0e000000) == 0 &&
6998 (insn & 0x00000090) != 0x90) ||
6999 ((insn & 0x0e000000) == (1 << 25))) {
7000 int set_cc, logic_cc, shiftop;
7001
7002 op1 = (insn >> 21) & 0xf;
7003 set_cc = (insn >> 20) & 1;
7004 logic_cc = table_logic_cc[op1] & set_cc;
7005
7006 /* data processing instruction */
7007 if (insn & (1 << 25)) {
7008 /* immediate operand */
7009 val = insn & 0xff;
7010 shift = ((insn >> 8) & 0xf) * 2;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007011 if (shift) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007012 val = (val >> shift) | (val << (32 - shift));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007013 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02007014 tmp2 = tcg_temp_new_i32();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007015 tcg_gen_movi_i32(tmp2, val);
7016 if (logic_cc && shift) {
7017 gen_set_CF_bit31(tmp2);
7018 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007019 } else {
7020 /* register */
7021 rm = (insn) & 0xf;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007022 tmp2 = load_reg(s, rm);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007023 shiftop = (insn >> 5) & 3;
7024 if (!(insn & (1 << 4))) {
7025 shift = (insn >> 7) & 0x1f;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007026 gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007027 } else {
7028 rs = (insn >> 8) & 0xf;
7029 tmp = load_reg(s, rs);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007030 gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007031 }
7032 }
7033 if (op1 != 0x0f && op1 != 0x0d) {
7034 rn = (insn >> 16) & 0xf;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007035 tmp = load_reg(s, rn);
7036 } else {
7037 TCGV_UNUSED(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007038 }
7039 rd = (insn >> 12) & 0xf;
7040 switch(op1) {
7041 case 0x00:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007042 tcg_gen_and_i32(tmp, tmp, tmp2);
7043 if (logic_cc) {
7044 gen_logic_CC(tmp);
7045 }
7046 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007047 break;
7048 case 0x01:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007049 tcg_gen_xor_i32(tmp, tmp, tmp2);
7050 if (logic_cc) {
7051 gen_logic_CC(tmp);
7052 }
7053 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007054 break;
7055 case 0x02:
7056 if (set_cc && rd == 15) {
7057 /* SUBS r15, ... is used for exception return. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007058 if (IS_USER(s)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007059 goto illegal_op;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007060 }
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007061 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007062 gen_exception_return(s, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007063 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007064 if (set_cc) {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007065 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007066 } else {
7067 tcg_gen_sub_i32(tmp, tmp, tmp2);
7068 }
7069 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007070 }
7071 break;
7072 case 0x03:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007073 if (set_cc) {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007074 gen_helper_sub_cc(tmp, cpu_env, tmp2, tmp);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007075 } else {
7076 tcg_gen_sub_i32(tmp, tmp2, tmp);
7077 }
7078 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007079 break;
7080 case 0x04:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007081 if (set_cc) {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007082 gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007083 } else {
7084 tcg_gen_add_i32(tmp, tmp, tmp2);
7085 }
7086 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007087 break;
7088 case 0x05:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007089 if (set_cc) {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007090 gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007091 } else {
7092 gen_add_carry(tmp, tmp, tmp2);
7093 }
7094 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007095 break;
7096 case 0x06:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007097 if (set_cc) {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007098 gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007099 } else {
7100 gen_sub_carry(tmp, tmp, tmp2);
7101 }
7102 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007103 break;
7104 case 0x07:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007105 if (set_cc) {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007106 gen_helper_sbc_cc(tmp, cpu_env, tmp2, tmp);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007107 } else {
7108 gen_sub_carry(tmp, tmp2, tmp);
7109 }
7110 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007111 break;
7112 case 0x08:
7113 if (set_cc) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007114 tcg_gen_and_i32(tmp, tmp, tmp2);
7115 gen_logic_CC(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007116 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02007117 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007118 break;
7119 case 0x09:
7120 if (set_cc) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007121 tcg_gen_xor_i32(tmp, tmp, tmp2);
7122 gen_logic_CC(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007123 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02007124 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007125 break;
7126 case 0x0a:
7127 if (set_cc) {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007128 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007129 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02007130 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007131 break;
7132 case 0x0b:
7133 if (set_cc) {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007134 gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007135 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02007136 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007137 break;
7138 case 0x0c:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007139 tcg_gen_or_i32(tmp, tmp, tmp2);
7140 if (logic_cc) {
7141 gen_logic_CC(tmp);
7142 }
7143 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007144 break;
7145 case 0x0d:
7146 if (logic_cc && rd == 15) {
7147 /* MOVS r15, ... is used for exception return. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007148 if (IS_USER(s)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007149 goto illegal_op;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007150 }
7151 gen_exception_return(s, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007152 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007153 if (logic_cc) {
7154 gen_logic_CC(tmp2);
7155 }
7156 store_reg_bx(env, s, rd, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007157 }
7158 break;
7159 case 0x0e:
David 'Digit' Turner52858642011-06-03 13:41:05 +02007160 tcg_gen_andc_i32(tmp, tmp, tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007161 if (logic_cc) {
7162 gen_logic_CC(tmp);
7163 }
7164 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007165 break;
7166 default:
7167 case 0x0f:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007168 tcg_gen_not_i32(tmp2, tmp2);
7169 if (logic_cc) {
7170 gen_logic_CC(tmp2);
7171 }
7172 store_reg_bx(env, s, rd, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007173 break;
7174 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007175 if (op1 != 0x0f && op1 != 0x0d) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007176 tcg_temp_free_i32(tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007177 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007178 } else {
7179 /* other instructions */
7180 op1 = (insn >> 24) & 0xf;
7181 switch(op1) {
7182 case 0x0:
7183 case 0x1:
7184 /* multiplies, extra load/stores */
7185 sh = (insn >> 5) & 3;
7186 if (sh == 0) {
7187 if (op1 == 0x0) {
7188 rd = (insn >> 16) & 0xf;
7189 rn = (insn >> 12) & 0xf;
7190 rs = (insn >> 8) & 0xf;
7191 rm = (insn) & 0xf;
7192 op1 = (insn >> 20) & 0xf;
7193 switch (op1) {
7194 case 0: case 1: case 2: case 3: case 6:
7195 /* 32 bit mul */
7196 tmp = load_reg(s, rs);
7197 tmp2 = load_reg(s, rm);
7198 tcg_gen_mul_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007199 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007200 if (insn & (1 << 22)) {
7201 /* Subtract (mls) */
7202 ARCH(6T2);
7203 tmp2 = load_reg(s, rn);
7204 tcg_gen_sub_i32(tmp, tmp2, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007205 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007206 } else if (insn & (1 << 21)) {
7207 /* Add */
7208 tmp2 = load_reg(s, rn);
7209 tcg_gen_add_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007210 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007211 }
7212 if (insn & (1 << 20))
7213 gen_logic_CC(tmp);
7214 store_reg(s, rd, tmp);
7215 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02007216 case 4:
7217 /* 64 bit mul double accumulate (UMAAL) */
7218 ARCH(6);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007219 tmp = load_reg(s, rs);
7220 tmp2 = load_reg(s, rm);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007221 tmp64 = gen_mulu_i64_i32(tmp, tmp2);
7222 gen_addq_lo(s, tmp64, rn);
7223 gen_addq_lo(s, tmp64, rd);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007224 gen_storeq_reg(s, rn, rd, tmp64);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007225 tcg_temp_free_i64(tmp64);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007226 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02007227 case 8: case 9: case 10: case 11:
7228 case 12: case 13: case 14: case 15:
7229 /* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */
7230 tmp = load_reg(s, rs);
7231 tmp2 = load_reg(s, rm);
7232 if (insn & (1 << 22)) {
7233 tmp64 = gen_muls_i64_i32(tmp, tmp2);
7234 } else {
7235 tmp64 = gen_mulu_i64_i32(tmp, tmp2);
7236 }
7237 if (insn & (1 << 21)) { /* mult accumulate */
7238 gen_addq(s, tmp64, rn, rd);
7239 }
7240 if (insn & (1 << 20)) {
7241 gen_logicq_cc(tmp64);
7242 }
7243 gen_storeq_reg(s, rn, rd, tmp64);
7244 tcg_temp_free_i64(tmp64);
7245 break;
7246 default:
7247 goto illegal_op;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007248 }
7249 } else {
7250 rn = (insn >> 16) & 0xf;
7251 rd = (insn >> 12) & 0xf;
7252 if (insn & (1 << 23)) {
7253 /* load/store exclusive */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007254 op1 = (insn >> 21) & 0x3;
7255 if (op1)
7256 ARCH(6K);
7257 else
7258 ARCH(6);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007259 addr = tcg_temp_local_new_i32();
7260 load_reg_var(s, addr, rn);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007261 if (insn & (1 << 20)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007262 switch (op1) {
7263 case 0: /* ldrex */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007264 gen_load_exclusive(s, rd, 15, addr, 2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007265 break;
7266 case 1: /* ldrexd */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007267 gen_load_exclusive(s, rd, rd + 1, addr, 3);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007268 break;
7269 case 2: /* ldrexb */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007270 gen_load_exclusive(s, rd, 15, addr, 0);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007271 break;
7272 case 3: /* ldrexh */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007273 gen_load_exclusive(s, rd, 15, addr, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007274 break;
7275 default:
7276 abort();
7277 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007278 } else {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007279 rm = insn & 0xf;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007280 switch (op1) {
7281 case 0: /* strex */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007282 gen_store_exclusive(s, rd, rm, 15, addr, 2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007283 break;
7284 case 1: /* strexd */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007285 gen_store_exclusive(s, rd, rm, rm + 1, addr, 3);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007286 break;
7287 case 2: /* strexb */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007288 gen_store_exclusive(s, rd, rm, 15, addr, 0);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007289 break;
7290 case 3: /* strexh */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007291 gen_store_exclusive(s, rd, rm, 15, addr, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007292 break;
7293 default:
7294 abort();
7295 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007296 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02007297 tcg_temp_free(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007298 } else {
7299 /* SWP instruction */
7300 rm = (insn) & 0xf;
7301
7302 /* ??? This is not really atomic. However we know
7303 we never have multiple CPUs running in parallel,
7304 so it is good enough. */
7305 addr = load_reg(s, rn);
7306 tmp = load_reg(s, rm);
7307 if (insn & (1 << 22)) {
7308 tmp2 = gen_ld8u(addr, IS_USER(s));
7309 gen_st8(tmp, addr, IS_USER(s));
7310 } else {
7311 tmp2 = gen_ld32(addr, IS_USER(s));
7312 gen_st32(tmp, addr, IS_USER(s));
7313 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02007314 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007315 store_reg(s, rd, tmp2);
7316 }
7317 }
7318 } else {
7319 int address_offset;
7320 int load;
7321 /* Misc load/store */
7322 rn = (insn >> 16) & 0xf;
7323 rd = (insn >> 12) & 0xf;
7324 addr = load_reg(s, rn);
7325 if (insn & (1 << 24))
7326 gen_add_datah_offset(s, insn, 0, addr);
7327 address_offset = 0;
7328 if (insn & (1 << 20)) {
7329 /* load */
7330 switch(sh) {
7331 case 1:
7332 tmp = gen_ld16u(addr, IS_USER(s));
7333 break;
7334 case 2:
7335 tmp = gen_ld8s(addr, IS_USER(s));
7336 break;
7337 default:
7338 case 3:
7339 tmp = gen_ld16s(addr, IS_USER(s));
7340 break;
7341 }
7342 load = 1;
7343 } else if (sh & 2) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007344 ARCH(5TE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007345 /* doubleword */
7346 if (sh & 1) {
7347 /* store */
7348 tmp = load_reg(s, rd);
7349 gen_st32(tmp, addr, IS_USER(s));
7350 tcg_gen_addi_i32(addr, addr, 4);
7351 tmp = load_reg(s, rd + 1);
7352 gen_st32(tmp, addr, IS_USER(s));
7353 load = 0;
7354 } else {
7355 /* load */
7356 tmp = gen_ld32(addr, IS_USER(s));
7357 store_reg(s, rd, tmp);
7358 tcg_gen_addi_i32(addr, addr, 4);
7359 tmp = gen_ld32(addr, IS_USER(s));
7360 rd++;
7361 load = 1;
7362 }
7363 address_offset = -4;
7364 } else {
7365 /* store */
7366 tmp = load_reg(s, rd);
7367 gen_st16(tmp, addr, IS_USER(s));
7368 load = 0;
7369 }
7370 /* Perform base writeback before the loaded value to
7371 ensure correct behavior with overlapping index registers.
7372 ldrd with base writeback is is undefined if the
7373 destination and index registers overlap. */
7374 if (!(insn & (1 << 24))) {
7375 gen_add_datah_offset(s, insn, address_offset, addr);
7376 store_reg(s, rn, addr);
7377 } else if (insn & (1 << 21)) {
7378 if (address_offset)
7379 tcg_gen_addi_i32(addr, addr, address_offset);
7380 store_reg(s, rn, addr);
7381 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007382 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007383 }
7384 if (load) {
7385 /* Complete the load. */
7386 store_reg(s, rd, tmp);
7387 }
7388 }
7389 break;
7390 case 0x4:
7391 case 0x5:
7392 goto do_ldst;
7393 case 0x6:
7394 case 0x7:
7395 if (insn & (1 << 4)) {
7396 ARCH(6);
7397 /* Armv6 Media instructions. */
7398 rm = insn & 0xf;
7399 rn = (insn >> 16) & 0xf;
7400 rd = (insn >> 12) & 0xf;
7401 rs = (insn >> 8) & 0xf;
7402 switch ((insn >> 23) & 3) {
7403 case 0: /* Parallel add/subtract. */
7404 op1 = (insn >> 20) & 7;
7405 tmp = load_reg(s, rn);
7406 tmp2 = load_reg(s, rm);
7407 sh = (insn >> 5) & 7;
7408 if ((op1 & 3) == 0 || sh == 5 || sh == 6)
7409 goto illegal_op;
7410 gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007411 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007412 store_reg(s, rd, tmp);
7413 break;
7414 case 1:
7415 if ((insn & 0x00700020) == 0) {
7416 /* Halfword pack. */
7417 tmp = load_reg(s, rn);
7418 tmp2 = load_reg(s, rm);
7419 shift = (insn >> 7) & 0x1f;
7420 if (insn & (1 << 6)) {
7421 /* pkhtb */
7422 if (shift == 0)
7423 shift = 31;
7424 tcg_gen_sari_i32(tmp2, tmp2, shift);
7425 tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
7426 tcg_gen_ext16u_i32(tmp2, tmp2);
7427 } else {
7428 /* pkhbt */
7429 if (shift)
7430 tcg_gen_shli_i32(tmp2, tmp2, shift);
7431 tcg_gen_ext16u_i32(tmp, tmp);
7432 tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
7433 }
7434 tcg_gen_or_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007435 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007436 store_reg(s, rd, tmp);
7437 } else if ((insn & 0x00200020) == 0x00200000) {
7438 /* [us]sat */
7439 tmp = load_reg(s, rm);
7440 shift = (insn >> 7) & 0x1f;
7441 if (insn & (1 << 6)) {
7442 if (shift == 0)
7443 shift = 31;
7444 tcg_gen_sari_i32(tmp, tmp, shift);
7445 } else {
7446 tcg_gen_shli_i32(tmp, tmp, shift);
7447 }
7448 sh = (insn >> 16) & 0x1f;
David 'Digit' Turner52858642011-06-03 13:41:05 +02007449 tmp2 = tcg_const_i32(sh);
7450 if (insn & (1 << 22))
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007451 gen_helper_usat(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007452 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007453 gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007454 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007455 store_reg(s, rd, tmp);
7456 } else if ((insn & 0x00300fe0) == 0x00200f20) {
7457 /* [us]sat16 */
7458 tmp = load_reg(s, rm);
7459 sh = (insn >> 16) & 0x1f;
David 'Digit' Turner52858642011-06-03 13:41:05 +02007460 tmp2 = tcg_const_i32(sh);
7461 if (insn & (1 << 22))
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007462 gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007463 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007464 gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007465 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007466 store_reg(s, rd, tmp);
7467 } else if ((insn & 0x00700fe0) == 0x00000fa0) {
7468 /* Select bytes. */
7469 tmp = load_reg(s, rn);
7470 tmp2 = load_reg(s, rm);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007471 tmp3 = tcg_temp_new_i32();
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01007472 tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007473 gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007474 tcg_temp_free_i32(tmp3);
7475 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007476 store_reg(s, rd, tmp);
7477 } else if ((insn & 0x000003e0) == 0x00000060) {
7478 tmp = load_reg(s, rm);
7479 shift = (insn >> 10) & 3;
David 'Digit' Turner52858642011-06-03 13:41:05 +02007480 /* ??? In many cases it's not necessary to do a
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007481 rotate, a shift is sufficient. */
7482 if (shift != 0)
David 'Digit' Turner52858642011-06-03 13:41:05 +02007483 tcg_gen_rotri_i32(tmp, tmp, shift * 8);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007484 op1 = (insn >> 20) & 7;
7485 switch (op1) {
7486 case 0: gen_sxtb16(tmp); break;
7487 case 2: gen_sxtb(tmp); break;
7488 case 3: gen_sxth(tmp); break;
7489 case 4: gen_uxtb16(tmp); break;
7490 case 6: gen_uxtb(tmp); break;
7491 case 7: gen_uxth(tmp); break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02007492 default: tcg_temp_free_i32(tmp); goto illegal_op;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007493 }
7494 if (rn != 15) {
7495 tmp2 = load_reg(s, rn);
7496 if ((op1 & 3) == 0) {
7497 gen_add16(tmp, tmp2);
7498 } else {
7499 tcg_gen_add_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007500 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007501 }
7502 }
7503 store_reg(s, rd, tmp);
7504 } else if ((insn & 0x003f0f60) == 0x003f0f20) {
7505 /* rev */
7506 tmp = load_reg(s, rm);
7507 if (insn & (1 << 22)) {
7508 if (insn & (1 << 7)) {
7509 gen_revsh(tmp);
7510 } else {
7511 ARCH(6T2);
7512 gen_helper_rbit(tmp, tmp);
7513 }
7514 } else {
7515 if (insn & (1 << 7))
7516 gen_rev16(tmp);
7517 else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007518 tcg_gen_bswap32_i32(tmp, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007519 }
7520 store_reg(s, rd, tmp);
7521 } else {
7522 goto illegal_op;
7523 }
7524 break;
7525 case 2: /* Multiplies (Type 3). */
7526 tmp = load_reg(s, rm);
7527 tmp2 = load_reg(s, rs);
7528 if (insn & (1 << 20)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007529 /* Signed multiply most significant [accumulate].
7530 (SMMUL, SMMLA, SMMLS) */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007531 tmp64 = gen_muls_i64_i32(tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007532
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007533 if (rd != 15) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007534 tmp = load_reg(s, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007535 if (insn & (1 << 6)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007536 tmp64 = gen_subq_msw(tmp64, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007537 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007538 tmp64 = gen_addq_msw(tmp64, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007539 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007540 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02007541 if (insn & (1 << 5)) {
7542 tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
7543 }
7544 tcg_gen_shri_i64(tmp64, tmp64, 32);
7545 tmp = tcg_temp_new_i32();
7546 tcg_gen_trunc_i64_i32(tmp, tmp64);
7547 tcg_temp_free_i64(tmp64);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007548 store_reg(s, rn, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007549 } else {
7550 if (insn & (1 << 5))
7551 gen_swap_half(tmp2);
7552 gen_smul_dual(tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007553 if (insn & (1 << 6)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007554 /* This subtraction cannot overflow. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007555 tcg_gen_sub_i32(tmp, tmp, tmp2);
7556 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007557 /* This addition cannot overflow 32 bits;
7558 * however it may overflow considered as a signed
7559 * operation, in which case we must set the Q flag.
7560 */
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007561 gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007562 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02007563 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007564 if (insn & (1 << 22)) {
7565 /* smlald, smlsld */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007566 tmp64 = tcg_temp_new_i64();
7567 tcg_gen_ext_i32_i64(tmp64, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007568 tcg_temp_free_i32(tmp);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007569 gen_addq(s, tmp64, rd, rn);
7570 gen_storeq_reg(s, rd, rn, tmp64);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007571 tcg_temp_free_i64(tmp64);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007572 } else {
7573 /* smuad, smusd, smlad, smlsd */
7574 if (rd != 15)
7575 {
7576 tmp2 = load_reg(s, rd);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007577 gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007578 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007579 }
7580 store_reg(s, rn, tmp);
7581 }
7582 }
7583 break;
7584 case 3:
7585 op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
7586 switch (op1) {
7587 case 0: /* Unsigned sum of absolute differences. */
7588 ARCH(6);
7589 tmp = load_reg(s, rm);
7590 tmp2 = load_reg(s, rs);
7591 gen_helper_usad8(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007592 tcg_temp_free_i32(tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007593 if (rd != 15) {
7594 tmp2 = load_reg(s, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007595 tcg_gen_add_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007596 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007597 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007598 store_reg(s, rn, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007599 break;
7600 case 0x20: case 0x24: case 0x28: case 0x2c:
7601 /* Bitfield insert/clear. */
7602 ARCH(6T2);
7603 shift = (insn >> 7) & 0x1f;
7604 i = (insn >> 16) & 0x1f;
7605 i = i + 1 - shift;
7606 if (rm == 15) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007607 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007608 tcg_gen_movi_i32(tmp, 0);
7609 } else {
7610 tmp = load_reg(s, rm);
7611 }
7612 if (i != 32) {
7613 tmp2 = load_reg(s, rd);
7614 gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007615 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007616 }
7617 store_reg(s, rd, tmp);
7618 break;
7619 case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
7620 case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007621 ARCH(6T2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007622 tmp = load_reg(s, rm);
7623 shift = (insn >> 7) & 0x1f;
7624 i = ((insn >> 16) & 0x1f) + 1;
7625 if (shift + i > 32)
7626 goto illegal_op;
7627 if (i < 32) {
7628 if (op1 & 0x20) {
7629 gen_ubfx(tmp, shift, (1u << i) - 1);
7630 } else {
7631 gen_sbfx(tmp, shift, i);
7632 }
7633 }
7634 store_reg(s, rd, tmp);
7635 break;
7636 default:
7637 goto illegal_op;
7638 }
7639 break;
7640 }
7641 break;
7642 }
7643 do_ldst:
7644 /* Check for undefined extension instructions
7645 * per the ARM Bible IE:
7646 * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx
7647 */
7648 sh = (0xf << 20) | (0xf << 4);
7649 if (op1 == 0x7 && ((insn & sh) == sh))
7650 {
7651 goto illegal_op;
7652 }
7653 /* load/store byte/word */
7654 rn = (insn >> 16) & 0xf;
7655 rd = (insn >> 12) & 0xf;
7656 tmp2 = load_reg(s, rn);
7657 i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
7658 if (insn & (1 << 24))
7659 gen_add_data_offset(s, insn, tmp2);
7660 if (insn & (1 << 20)) {
7661 /* load */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007662 if (insn & (1 << 22)) {
7663 tmp = gen_ld8u(tmp2, i);
7664 } else {
7665 tmp = gen_ld32(tmp2, i);
7666 }
7667 } else {
7668 /* store */
7669 tmp = load_reg(s, rd);
7670 if (insn & (1 << 22))
7671 gen_st8(tmp, tmp2, i);
7672 else
7673 gen_st32(tmp, tmp2, i);
7674 }
7675 if (!(insn & (1 << 24))) {
7676 gen_add_data_offset(s, insn, tmp2);
7677 store_reg(s, rn, tmp2);
7678 } else if (insn & (1 << 21)) {
7679 store_reg(s, rn, tmp2);
7680 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007681 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007682 }
7683 if (insn & (1 << 20)) {
7684 /* Complete the load. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007685 store_reg_from_load(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007686 }
7687 break;
7688 case 0x08:
7689 case 0x09:
7690 {
7691 int j, n, user, loaded_base;
7692 TCGv loaded_var;
7693 /* load/store multiple words */
7694 /* XXX: store correct base if write back */
7695 user = 0;
7696 if (insn & (1 << 22)) {
7697 if (IS_USER(s))
7698 goto illegal_op; /* only usable in supervisor mode */
7699
7700 if ((insn & (1 << 15)) == 0)
7701 user = 1;
7702 }
7703 rn = (insn >> 16) & 0xf;
7704 addr = load_reg(s, rn);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007705 tmp3 = tcg_const_i32(4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007706
7707 /* compute total size */
7708 loaded_base = 0;
7709 TCGV_UNUSED(loaded_var);
7710 n = 0;
7711 for(i=0;i<16;i++) {
7712 if (insn & (1 << i))
7713 n++;
7714 }
7715 /* XXX: test invalid n == 0 case ? */
7716 if (insn & (1 << 23)) {
7717 if (insn & (1 << 24)) {
7718 /* pre increment */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007719 tcg_gen_add_i32(addr, addr, tmp3);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007720 } else {
7721 /* post increment */
7722 }
7723 } else {
7724 if (insn & (1 << 24)) {
7725 /* pre decrement */
7726 tcg_gen_addi_i32(addr, addr, -(n * 4));
7727 } else {
7728 /* post decrement */
7729 if (n != 1)
7730 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
7731 }
7732 }
7733 j = 0;
7734 for(i=0;i<16;i++) {
7735 if (insn & (1 << i)) {
7736 if (insn & (1 << 20)) {
7737 /* load */
7738 tmp = gen_ld32(addr, IS_USER(s));
David 'Digit' Turner52858642011-06-03 13:41:05 +02007739 if (user) {
7740 tmp2 = tcg_const_i32(i);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007741 gen_helper_set_user_reg(cpu_env, tmp2, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007742 tcg_temp_free_i32(tmp2);
7743 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007744 } else if (i == rn) {
7745 loaded_var = tmp;
7746 loaded_base = 1;
7747 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007748 store_reg_from_load(env, s, i, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007749 }
7750 } else {
7751 /* store */
7752 if (i == 15) {
7753 /* special case: r15 = PC + 8 */
7754 val = (long)s->pc + 4;
David 'Digit' Turner52858642011-06-03 13:41:05 +02007755 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007756 tcg_gen_movi_i32(tmp, val);
7757 } else if (user) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007758 tmp = tcg_temp_new_i32();
7759 tmp2 = tcg_const_i32(i);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007760 gen_helper_get_user_reg(tmp, cpu_env, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007761 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007762 } else {
7763 tmp = load_reg(s, i);
7764 }
7765 gen_st32(tmp, addr, IS_USER(s));
7766 }
7767 j++;
7768 /* no need to add after the last transfer */
7769 if (j != n)
David 'Digit' Turner52858642011-06-03 13:41:05 +02007770 tcg_gen_add_i32(addr, addr, tmp3);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007771 }
7772 }
7773 if (insn & (1 << 21)) {
7774 /* write back */
7775 if (insn & (1 << 23)) {
7776 if (insn & (1 << 24)) {
7777 /* pre increment */
7778 } else {
7779 /* post increment */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007780 tcg_gen_add_i32(addr, addr, tmp3);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007781 }
7782 } else {
7783 if (insn & (1 << 24)) {
7784 /* pre decrement */
7785 if (n != 1)
7786 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
7787 } else {
7788 /* post decrement */
7789 tcg_gen_addi_i32(addr, addr, -(n * 4));
7790 }
7791 }
7792 store_reg(s, rn, addr);
7793 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007794 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007795 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02007796 tcg_temp_free_i32(tmp3);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007797 if (loaded_base) {
7798 store_reg(s, rn, loaded_var);
7799 }
7800 if ((insn & (1 << 22)) && !user) {
7801 /* Restore CPSR from SPSR. */
7802 tmp = load_cpu_field(spsr);
7803 gen_set_cpsr(tmp, 0xffffffff);
David 'Digit' Turner52858642011-06-03 13:41:05 +02007804 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007805 s->is_jmp = DISAS_UPDATE;
7806 }
7807 }
7808 break;
7809 case 0xa:
7810 case 0xb:
7811 {
7812 int32_t offset;
David 'Digit' Turner52858642011-06-03 13:41:05 +02007813
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007814 /* branch (and link) */
7815 val = (int32_t)s->pc;
7816 if (insn & (1 << 24)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007817 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007818 tcg_gen_movi_i32(tmp, val);
7819 store_reg(s, 14, tmp);
7820 }
7821 offset = (((int32_t)insn << 8) >> 8);
7822 val += (offset << 2) + 4;
7823 gen_jmp(s, val);
7824 }
7825 break;
7826 case 0xc:
7827 case 0xd:
7828 case 0xe:
7829 /* Coprocessor. */
7830 if (disas_coproc_insn(env, s, insn))
7831 goto illegal_op;
7832 break;
7833 case 0xf:
7834 /* swi */
7835 gen_set_pc_im(s->pc);
7836 s->is_jmp = DISAS_SWI;
7837 break;
7838 default:
7839 illegal_op:
David 'Digit' Turner52858642011-06-03 13:41:05 +02007840 gen_exception_insn(s, 4, EXCP_UDEF);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007841 break;
7842 }
7843 }
7844}
7845
7846/* Return true if this is a Thumb-2 logical op. */
7847static int
7848thumb2_logic_op(int op)
7849{
7850 return (op < 8);
7851}
7852
7853/* Generate code for a Thumb-2 data processing operation. If CONDS is nonzero
7854 then set condition code flags based on the result of the operation.
7855 If SHIFTER_OUT is nonzero then set the carry flag for logical operations
7856 to the high bit of T1.
7857 Returns zero if the opcode is valid. */
7858
7859static int
David 'Digit' Turner52858642011-06-03 13:41:05 +02007860gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCGv t0, TCGv t1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007861{
7862 int logic_cc;
7863
7864 logic_cc = 0;
7865 switch (op) {
7866 case 0: /* and */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007867 tcg_gen_and_i32(t0, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007868 logic_cc = conds;
7869 break;
7870 case 1: /* bic */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007871 tcg_gen_andc_i32(t0, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007872 logic_cc = conds;
7873 break;
7874 case 2: /* orr */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007875 tcg_gen_or_i32(t0, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007876 logic_cc = conds;
7877 break;
7878 case 3: /* orn */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007879 tcg_gen_orc_i32(t0, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007880 logic_cc = conds;
7881 break;
7882 case 4: /* eor */
David 'Digit' Turner52858642011-06-03 13:41:05 +02007883 tcg_gen_xor_i32(t0, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007884 logic_cc = conds;
7885 break;
7886 case 8: /* add */
7887 if (conds)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007888 gen_helper_add_cc(t0, cpu_env, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007889 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02007890 tcg_gen_add_i32(t0, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007891 break;
7892 case 10: /* adc */
7893 if (conds)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007894 gen_helper_adc_cc(t0, cpu_env, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007895 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02007896 gen_adc(t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007897 break;
7898 case 11: /* sbc */
7899 if (conds)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007900 gen_helper_sbc_cc(t0, cpu_env, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007901 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02007902 gen_sub_carry(t0, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007903 break;
7904 case 13: /* sub */
7905 if (conds)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007906 gen_helper_sub_cc(t0, cpu_env, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007907 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02007908 tcg_gen_sub_i32(t0, t0, t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007909 break;
7910 case 14: /* rsb */
7911 if (conds)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02007912 gen_helper_sub_cc(t0, cpu_env, t1, t0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007913 else
David 'Digit' Turner52858642011-06-03 13:41:05 +02007914 tcg_gen_sub_i32(t0, t1, t0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007915 break;
7916 default: /* 5, 6, 7, 9, 12, 15. */
7917 return 1;
7918 }
7919 if (logic_cc) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007920 gen_logic_CC(t0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007921 if (shifter_out)
David 'Digit' Turner52858642011-06-03 13:41:05 +02007922 gen_set_CF_bit31(t1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007923 }
7924 return 0;
7925}
7926
7927/* Translate a 32-bit thumb instruction. Returns nonzero if the instruction
7928 is not legal. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01007929static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw1)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007930{
7931 uint32_t insn, imm, shift, offset;
7932 uint32_t rd, rn, rm, rs;
7933 TCGv tmp;
7934 TCGv tmp2;
7935 TCGv tmp3;
7936 TCGv addr;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07007937 TCGv_i64 tmp64;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007938 int op;
7939 int shiftop;
7940 int conds;
7941 int logic_cc;
7942
7943 if (!(arm_feature(env, ARM_FEATURE_THUMB2)
7944 || arm_feature (env, ARM_FEATURE_M))) {
7945 /* Thumb-1 cores may need to treat bl and blx as a pair of
7946 16-bit instructions to get correct prefetch abort behavior. */
7947 insn = insn_hw1;
7948 if ((insn & (1 << 12)) == 0) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02007949 ARCH(5);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007950 /* Second half of blx. */
7951 offset = ((insn & 0x7ff) << 1);
7952 tmp = load_reg(s, 14);
7953 tcg_gen_addi_i32(tmp, tmp, offset);
7954 tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
7955
David 'Digit' Turner52858642011-06-03 13:41:05 +02007956 tmp2 = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007957 tcg_gen_movi_i32(tmp2, s->pc | 1);
7958 store_reg(s, 14, tmp2);
7959 gen_bx(s, tmp);
7960 return 0;
7961 }
7962 if (insn & (1 << 11)) {
7963 /* Second half of bl. */
7964 offset = ((insn & 0x7ff) << 1) | 1;
7965 tmp = load_reg(s, 14);
7966 tcg_gen_addi_i32(tmp, tmp, offset);
7967
David 'Digit' Turner52858642011-06-03 13:41:05 +02007968 tmp2 = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007969 tcg_gen_movi_i32(tmp2, s->pc | 1);
7970 store_reg(s, 14, tmp2);
7971 gen_bx(s, tmp);
7972 return 0;
7973 }
7974 if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
7975 /* Instruction spans a page boundary. Implement it as two
7976 16-bit instructions in case the second half causes an
7977 prefetch abort. */
7978 offset = ((int32_t)insn << 21) >> 9;
David 'Digit' Turner52858642011-06-03 13:41:05 +02007979 tcg_gen_movi_i32(cpu_R[14], s->pc + 2 + offset);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007980 return 0;
7981 }
7982 /* Fall through to 32-bit decode. */
7983 }
7984
David 'Digit' Turnereca7bc22014-03-14 23:58:39 +01007985 insn = cpu_lduw_code(env, s->pc);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08007986 s->pc += 2;
David 'Digit' Turner52858642011-06-03 13:41:05 +02007987 insn |= (uint32_t)insn_hw1 << 16;
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08007988
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08007989 if ((insn & 0xf800e800) != 0xf000e800) {
7990 ARCH(6T2);
7991 }
7992
7993 rn = (insn >> 16) & 0xf;
7994 rs = (insn >> 12) & 0xf;
7995 rd = (insn >> 8) & 0xf;
7996 rm = insn & 0xf;
7997 switch ((insn >> 25) & 0xf) {
7998 case 0: case 1: case 2: case 3:
7999 /* 16-bit instructions. Should never happen. */
8000 abort();
8001 case 4:
8002 if (insn & (1 << 22)) {
8003 /* Other load/store, table branch. */
8004 if (insn & 0x01200000) {
8005 /* Load/store doubleword. */
8006 if (rn == 15) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008007 addr = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008008 tcg_gen_movi_i32(addr, s->pc & ~3);
8009 } else {
8010 addr = load_reg(s, rn);
8011 }
8012 offset = (insn & 0xff) * 4;
8013 if ((insn & (1 << 23)) == 0)
8014 offset = -offset;
8015 if (insn & (1 << 24)) {
8016 tcg_gen_addi_i32(addr, addr, offset);
8017 offset = 0;
8018 }
8019 if (insn & (1 << 20)) {
8020 /* ldrd */
8021 tmp = gen_ld32(addr, IS_USER(s));
8022 store_reg(s, rs, tmp);
8023 tcg_gen_addi_i32(addr, addr, 4);
8024 tmp = gen_ld32(addr, IS_USER(s));
8025 store_reg(s, rd, tmp);
8026 } else {
8027 /* strd */
8028 tmp = load_reg(s, rs);
8029 gen_st32(tmp, addr, IS_USER(s));
8030 tcg_gen_addi_i32(addr, addr, 4);
8031 tmp = load_reg(s, rd);
8032 gen_st32(tmp, addr, IS_USER(s));
8033 }
8034 if (insn & (1 << 21)) {
8035 /* Base writeback. */
8036 if (rn == 15)
8037 goto illegal_op;
8038 tcg_gen_addi_i32(addr, addr, offset - 4);
8039 store_reg(s, rn, addr);
8040 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008041 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008042 }
8043 } else if ((insn & (1 << 23)) == 0) {
8044 /* Load/store exclusive word. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008045 addr = tcg_temp_local_new();
8046 load_reg_var(s, addr, rn);
8047 tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008048 if (insn & (1 << 20)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008049 gen_load_exclusive(s, rs, 15, addr, 2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008050 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008051 gen_store_exclusive(s, rd, rs, 15, addr, 2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008052 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008053 tcg_temp_free(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008054 } else if ((insn & (1 << 6)) == 0) {
8055 /* Table Branch. */
8056 if (rn == 15) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008057 addr = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008058 tcg_gen_movi_i32(addr, s->pc);
8059 } else {
8060 addr = load_reg(s, rn);
8061 }
8062 tmp = load_reg(s, rm);
8063 tcg_gen_add_i32(addr, addr, tmp);
8064 if (insn & (1 << 4)) {
8065 /* tbh */
8066 tcg_gen_add_i32(addr, addr, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008067 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008068 tmp = gen_ld16u(addr, IS_USER(s));
8069 } else { /* tbb */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008070 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008071 tmp = gen_ld8u(addr, IS_USER(s));
8072 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008073 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008074 tcg_gen_shli_i32(tmp, tmp, 1);
8075 tcg_gen_addi_i32(tmp, tmp, s->pc);
8076 store_reg(s, 15, tmp);
8077 } else {
8078 /* Load/store exclusive byte/halfword/doubleword. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008079 ARCH(7);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008080 op = (insn >> 4) & 0x3;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008081 if (op == 2) {
8082 goto illegal_op;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008083 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008084 addr = tcg_temp_local_new();
8085 load_reg_var(s, addr, rn);
8086 if (insn & (1 << 20)) {
8087 gen_load_exclusive(s, rs, rd, addr, op);
8088 } else {
8089 gen_store_exclusive(s, rm, rs, rd, addr, op);
8090 }
8091 tcg_temp_free(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008092 }
8093 } else {
8094 /* Load/store multiple, RFE, SRS. */
8095 if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
8096 /* Not available in user mode. */
8097 if (IS_USER(s))
8098 goto illegal_op;
8099 if (insn & (1 << 20)) {
8100 /* rfe */
8101 addr = load_reg(s, rn);
8102 if ((insn & (1 << 24)) == 0)
8103 tcg_gen_addi_i32(addr, addr, -8);
8104 /* Load PC into tmp and CPSR into tmp2. */
8105 tmp = gen_ld32(addr, 0);
8106 tcg_gen_addi_i32(addr, addr, 4);
8107 tmp2 = gen_ld32(addr, 0);
8108 if (insn & (1 << 21)) {
8109 /* Base writeback. */
8110 if (insn & (1 << 24)) {
8111 tcg_gen_addi_i32(addr, addr, 4);
8112 } else {
8113 tcg_gen_addi_i32(addr, addr, -4);
8114 }
8115 store_reg(s, rn, addr);
8116 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008117 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008118 }
8119 gen_rfe(s, tmp, tmp2);
8120 } else {
8121 /* srs */
8122 op = (insn & 0x1f);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008123 addr = tcg_temp_new_i32();
8124 tmp = tcg_const_i32(op);
8125 gen_helper_get_r13_banked(addr, cpu_env, tmp);
8126 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008127 if ((insn & (1 << 24)) == 0) {
8128 tcg_gen_addi_i32(addr, addr, -8);
8129 }
8130 tmp = load_reg(s, 14);
8131 gen_st32(tmp, addr, 0);
8132 tcg_gen_addi_i32(addr, addr, 4);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008133 tmp = tcg_temp_new_i32();
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008134 gen_helper_cpsr_read(tmp, cpu_env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008135 gen_st32(tmp, addr, 0);
8136 if (insn & (1 << 21)) {
8137 if ((insn & (1 << 24)) == 0) {
8138 tcg_gen_addi_i32(addr, addr, -4);
8139 } else {
8140 tcg_gen_addi_i32(addr, addr, 4);
8141 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008142 tmp = tcg_const_i32(op);
8143 gen_helper_set_r13_banked(cpu_env, tmp, addr);
8144 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008145 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008146 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008147 }
8148 }
8149 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008150 int i, loaded_base = 0;
8151 TCGv loaded_var;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008152 /* Load/store multiple. */
8153 addr = load_reg(s, rn);
8154 offset = 0;
8155 for (i = 0; i < 16; i++) {
8156 if (insn & (1 << i))
8157 offset += 4;
8158 }
8159 if (insn & (1 << 24)) {
8160 tcg_gen_addi_i32(addr, addr, -offset);
8161 }
8162
David 'Digit' Turner52858642011-06-03 13:41:05 +02008163 TCGV_UNUSED(loaded_var);
8164 tmp2 = tcg_const_i32(4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008165 for (i = 0; i < 16; i++) {
8166 if ((insn & (1 << i)) == 0)
8167 continue;
8168 if (insn & (1 << 20)) {
8169 /* Load. */
8170 tmp = gen_ld32(addr, IS_USER(s));
8171 if (i == 15) {
8172 gen_bx(s, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008173 } else if (i == rn) {
8174 loaded_var = tmp;
8175 loaded_base = 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008176 } else {
8177 store_reg(s, i, tmp);
8178 }
8179 } else {
8180 /* Store. */
8181 tmp = load_reg(s, i);
8182 gen_st32(tmp, addr, IS_USER(s));
8183 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008184 tcg_gen_add_i32(addr, addr, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008185 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008186 if (loaded_base) {
8187 store_reg(s, rn, loaded_var);
8188 }
8189 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008190 if (insn & (1 << 21)) {
8191 /* Base register writeback. */
8192 if (insn & (1 << 24)) {
8193 tcg_gen_addi_i32(addr, addr, -offset);
8194 }
8195 /* Fault if writeback register is in register list. */
8196 if (insn & (1 << rn))
8197 goto illegal_op;
8198 store_reg(s, rn, addr);
8199 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008200 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008201 }
8202 }
8203 }
8204 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008205 case 5:
8206
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008207 op = (insn >> 21) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008208 if (op == 6) {
8209 /* Halfword pack. */
8210 tmp = load_reg(s, rn);
8211 tmp2 = load_reg(s, rm);
8212 shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3);
8213 if (insn & (1 << 5)) {
8214 /* pkhtb */
8215 if (shift == 0)
8216 shift = 31;
8217 tcg_gen_sari_i32(tmp2, tmp2, shift);
8218 tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
8219 tcg_gen_ext16u_i32(tmp2, tmp2);
8220 } else {
8221 /* pkhbt */
8222 if (shift)
8223 tcg_gen_shli_i32(tmp2, tmp2, shift);
8224 tcg_gen_ext16u_i32(tmp, tmp);
8225 tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
8226 }
8227 tcg_gen_or_i32(tmp, tmp, tmp2);
8228 tcg_temp_free_i32(tmp2);
8229 store_reg(s, rd, tmp);
8230 } else {
8231 /* Data processing register constant shift. */
8232 if (rn == 15) {
8233 tmp = tcg_temp_new_i32();
8234 tcg_gen_movi_i32(tmp, 0);
8235 } else {
8236 tmp = load_reg(s, rn);
8237 }
8238 tmp2 = load_reg(s, rm);
8239
8240 shiftop = (insn >> 4) & 3;
8241 shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
8242 conds = (insn & (1 << 20)) != 0;
8243 logic_cc = (conds && thumb2_logic_op(op));
8244 gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
8245 if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
8246 goto illegal_op;
8247 tcg_temp_free_i32(tmp2);
8248 if (rd != 15) {
8249 store_reg(s, rd, tmp);
8250 } else {
8251 tcg_temp_free_i32(tmp);
8252 }
8253 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008254 break;
8255 case 13: /* Misc data processing. */
8256 op = ((insn >> 22) & 6) | ((insn >> 7) & 1);
8257 if (op < 4 && (insn & 0xf000) != 0xf000)
8258 goto illegal_op;
8259 switch (op) {
8260 case 0: /* Register controlled shift. */
8261 tmp = load_reg(s, rn);
8262 tmp2 = load_reg(s, rm);
8263 if ((insn & 0x70) != 0)
8264 goto illegal_op;
8265 op = (insn >> 21) & 3;
8266 logic_cc = (insn & (1 << 20)) != 0;
8267 gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
8268 if (logic_cc)
8269 gen_logic_CC(tmp);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008270 store_reg_bx(env, s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008271 break;
8272 case 1: /* Sign/zero extend. */
8273 tmp = load_reg(s, rm);
8274 shift = (insn >> 4) & 3;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008275 /* ??? In many cases it's not necessary to do a
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008276 rotate, a shift is sufficient. */
8277 if (shift != 0)
David 'Digit' Turner52858642011-06-03 13:41:05 +02008278 tcg_gen_rotri_i32(tmp, tmp, shift * 8);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008279 op = (insn >> 20) & 7;
8280 switch (op) {
8281 case 0: gen_sxth(tmp); break;
8282 case 1: gen_uxth(tmp); break;
8283 case 2: gen_sxtb16(tmp); break;
8284 case 3: gen_uxtb16(tmp); break;
8285 case 4: gen_sxtb(tmp); break;
8286 case 5: gen_uxtb(tmp); break;
8287 default: goto illegal_op;
8288 }
8289 if (rn != 15) {
8290 tmp2 = load_reg(s, rn);
8291 if ((op >> 1) == 1) {
8292 gen_add16(tmp, tmp2);
8293 } else {
8294 tcg_gen_add_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008295 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008296 }
8297 }
8298 store_reg(s, rd, tmp);
8299 break;
8300 case 2: /* SIMD add/subtract. */
8301 op = (insn >> 20) & 7;
8302 shift = (insn >> 4) & 7;
8303 if ((op & 3) == 3 || (shift & 3) == 3)
8304 goto illegal_op;
8305 tmp = load_reg(s, rn);
8306 tmp2 = load_reg(s, rm);
8307 gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008308 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008309 store_reg(s, rd, tmp);
8310 break;
8311 case 3: /* Other data processing. */
8312 op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
8313 if (op < 4) {
8314 /* Saturating add/subtract. */
8315 tmp = load_reg(s, rn);
8316 tmp2 = load_reg(s, rm);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008317 if (op & 1)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008318 gen_helper_double_saturate(tmp, cpu_env, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008319 if (op & 2)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008320 gen_helper_sub_saturate(tmp, cpu_env, tmp2, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008321 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008322 gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008323 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008324 } else {
8325 tmp = load_reg(s, rn);
8326 switch (op) {
8327 case 0x0a: /* rbit */
8328 gen_helper_rbit(tmp, tmp);
8329 break;
8330 case 0x08: /* rev */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008331 tcg_gen_bswap32_i32(tmp, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008332 break;
8333 case 0x09: /* rev16 */
8334 gen_rev16(tmp);
8335 break;
8336 case 0x0b: /* revsh */
8337 gen_revsh(tmp);
8338 break;
8339 case 0x10: /* sel */
8340 tmp2 = load_reg(s, rm);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008341 tmp3 = tcg_temp_new_i32();
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01008342 tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008343 gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008344 tcg_temp_free_i32(tmp3);
8345 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008346 break;
8347 case 0x18: /* clz */
8348 gen_helper_clz(tmp, tmp);
8349 break;
8350 default:
8351 goto illegal_op;
8352 }
8353 }
8354 store_reg(s, rd, tmp);
8355 break;
8356 case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */
8357 op = (insn >> 4) & 0xf;
8358 tmp = load_reg(s, rn);
8359 tmp2 = load_reg(s, rm);
8360 switch ((insn >> 20) & 7) {
8361 case 0: /* 32 x 32 -> 32 */
8362 tcg_gen_mul_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008363 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008364 if (rs != 15) {
8365 tmp2 = load_reg(s, rs);
8366 if (op)
8367 tcg_gen_sub_i32(tmp, tmp2, tmp);
8368 else
8369 tcg_gen_add_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008370 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008371 }
8372 break;
8373 case 1: /* 16 x 16 -> 32 */
8374 gen_mulxy(tmp, tmp2, op & 2, op & 1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008375 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008376 if (rs != 15) {
8377 tmp2 = load_reg(s, rs);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008378 gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008379 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008380 }
8381 break;
8382 case 2: /* Dual multiply add. */
8383 case 4: /* Dual multiply subtract. */
8384 if (op)
8385 gen_swap_half(tmp2);
8386 gen_smul_dual(tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008387 if (insn & (1 << 22)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008388 /* This subtraction cannot overflow. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008389 tcg_gen_sub_i32(tmp, tmp, tmp2);
8390 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008391 /* This addition cannot overflow 32 bits;
8392 * however it may overflow considered as a signed
8393 * operation, in which case we must set the Q flag.
8394 */
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008395 gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008396 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008397 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008398 if (rs != 15)
8399 {
8400 tmp2 = load_reg(s, rs);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008401 gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008402 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008403 }
8404 break;
8405 case 3: /* 32 * 16 -> 32msb */
8406 if (op)
8407 tcg_gen_sari_i32(tmp2, tmp2, 16);
8408 else
8409 gen_sxth(tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008410 tmp64 = gen_muls_i64_i32(tmp, tmp2);
8411 tcg_gen_shri_i64(tmp64, tmp64, 16);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008412 tmp = tcg_temp_new_i32();
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008413 tcg_gen_trunc_i64_i32(tmp, tmp64);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008414 tcg_temp_free_i64(tmp64);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008415 if (rs != 15)
8416 {
8417 tmp2 = load_reg(s, rs);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008418 gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008419 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008420 }
8421 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008422 case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
8423 tmp64 = gen_muls_i64_i32(tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008424 if (rs != 15) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008425 tmp = load_reg(s, rs);
8426 if (insn & (1 << 20)) {
8427 tmp64 = gen_addq_msw(tmp64, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008428 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008429 tmp64 = gen_subq_msw(tmp64, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008430 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008431 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008432 if (insn & (1 << 4)) {
8433 tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
8434 }
8435 tcg_gen_shri_i64(tmp64, tmp64, 32);
8436 tmp = tcg_temp_new_i32();
8437 tcg_gen_trunc_i64_i32(tmp, tmp64);
8438 tcg_temp_free_i64(tmp64);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008439 break;
8440 case 7: /* Unsigned sum of absolute differences. */
8441 gen_helper_usad8(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008442 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008443 if (rs != 15) {
8444 tmp2 = load_reg(s, rs);
8445 tcg_gen_add_i32(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008446 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008447 }
8448 break;
8449 }
8450 store_reg(s, rd, tmp);
8451 break;
8452 case 6: case 7: /* 64-bit multiply, Divide. */
8453 op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
8454 tmp = load_reg(s, rn);
8455 tmp2 = load_reg(s, rm);
8456 if ((op & 0x50) == 0x10) {
8457 /* sdiv, udiv */
8458 if (!arm_feature(env, ARM_FEATURE_DIV))
8459 goto illegal_op;
8460 if (op & 0x20)
8461 gen_helper_udiv(tmp, tmp, tmp2);
8462 else
8463 gen_helper_sdiv(tmp, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008464 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008465 store_reg(s, rd, tmp);
8466 } else if ((op & 0xe) == 0xc) {
8467 /* Dual multiply accumulate long. */
8468 if (op & 1)
8469 gen_swap_half(tmp2);
8470 gen_smul_dual(tmp, tmp2);
8471 if (op & 0x10) {
8472 tcg_gen_sub_i32(tmp, tmp, tmp2);
8473 } else {
8474 tcg_gen_add_i32(tmp, tmp, tmp2);
8475 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008476 tcg_temp_free_i32(tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008477 /* BUGFIX */
8478 tmp64 = tcg_temp_new_i64();
8479 tcg_gen_ext_i32_i64(tmp64, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008480 tcg_temp_free_i32(tmp);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008481 gen_addq(s, tmp64, rs, rd);
8482 gen_storeq_reg(s, rs, rd, tmp64);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008483 tcg_temp_free_i64(tmp64);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008484 } else {
8485 if (op & 0x20) {
8486 /* Unsigned 64-bit multiply */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008487 tmp64 = gen_mulu_i64_i32(tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008488 } else {
8489 if (op & 8) {
8490 /* smlalxy */
8491 gen_mulxy(tmp, tmp2, op & 2, op & 1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008492 tcg_temp_free_i32(tmp2);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008493 tmp64 = tcg_temp_new_i64();
8494 tcg_gen_ext_i32_i64(tmp64, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008495 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008496 } else {
8497 /* Signed 64-bit multiply */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008498 tmp64 = gen_muls_i64_i32(tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008499 }
8500 }
8501 if (op & 4) {
8502 /* umaal */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008503 gen_addq_lo(s, tmp64, rs);
8504 gen_addq_lo(s, tmp64, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008505 } else if (op & 0x40) {
8506 /* 64-bit accumulate. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008507 gen_addq(s, tmp64, rs, rd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008508 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07008509 gen_storeq_reg(s, rs, rd, tmp64);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008510 tcg_temp_free_i64(tmp64);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008511 }
8512 break;
8513 }
8514 break;
8515 case 6: case 7: case 14: case 15:
8516 /* Coprocessor. */
8517 if (((insn >> 24) & 3) == 3) {
8518 /* Translate into the equivalent ARM encoding. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008519 insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008520 if (disas_neon_data_insn(env, s, insn))
8521 goto illegal_op;
8522 } else {
8523 if (insn & (1 << 28))
8524 goto illegal_op;
8525 if (disas_coproc_insn (env, s, insn))
8526 goto illegal_op;
8527 }
8528 break;
8529 case 8: case 9: case 10: case 11:
8530 if (insn & (1 << 15)) {
8531 /* Branches, misc control. */
8532 if (insn & 0x5000) {
8533 /* Unconditional branch. */
8534 /* signextend(hw1[10:0]) -> offset[:12]. */
8535 offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff;
8536 /* hw1[10:0] -> offset[11:1]. */
8537 offset |= (insn & 0x7ff) << 1;
8538 /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22]
8539 offset[24:22] already have the same value because of the
8540 sign extension above. */
8541 offset ^= ((~insn) & (1 << 13)) << 10;
8542 offset ^= ((~insn) & (1 << 11)) << 11;
8543
8544 if (insn & (1 << 14)) {
8545 /* Branch and link. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008546 tcg_gen_movi_i32(cpu_R[14], s->pc | 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008547 }
8548
8549 offset += s->pc;
8550 if (insn & (1 << 12)) {
8551 /* b/bl */
8552 gen_jmp(s, offset);
8553 } else {
8554 /* blx */
8555 offset &= ~(uint32_t)2;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008556 /* thumb2 bx, no need to check */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008557 gen_bx_im(s, offset);
8558 }
8559 } else if (((insn >> 23) & 7) == 7) {
8560 /* Misc control */
8561 if (insn & (1 << 13))
8562 goto illegal_op;
8563
8564 if (insn & (1 << 26)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008565 /* Secure monitor call / smc (v6Z) */
8566 if (!(env->cp15.c0_c2[4] & 0xf000) || IS_USER(s)) {
8567 goto illegal_op;
8568 }
8569 gen_smc(env, s);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008570 } else {
8571 op = (insn >> 20) & 7;
8572 switch (op) {
8573 case 0: /* msr cpsr. */
8574 if (IS_M(env)) {
8575 tmp = load_reg(s, rn);
8576 addr = tcg_const_i32(insn & 0xff);
8577 gen_helper_v7m_msr(cpu_env, addr, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008578 tcg_temp_free_i32(addr);
8579 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008580 gen_lookup_tb(s);
8581 break;
8582 }
8583 /* fall through */
8584 case 1: /* msr spsr. */
8585 if (IS_M(env))
8586 goto illegal_op;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008587 tmp = load_reg(s, rn);
8588 if (gen_set_psr(s,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008589 msr_mask(env, s, (insn >> 8) & 0xf, op == 1),
David 'Digit' Turner52858642011-06-03 13:41:05 +02008590 op == 1, tmp))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008591 goto illegal_op;
8592 break;
8593 case 2: /* cps, nop-hint. */
8594 if (((insn >> 8) & 7) == 0) {
8595 gen_nop_hint(s, insn & 0xff);
8596 }
8597 /* Implemented as NOP in user mode. */
8598 if (IS_USER(s))
8599 break;
8600 offset = 0;
8601 imm = 0;
8602 if (insn & (1 << 10)) {
8603 if (insn & (1 << 7))
8604 offset |= CPSR_A;
8605 if (insn & (1 << 6))
8606 offset |= CPSR_I;
8607 if (insn & (1 << 5))
8608 offset |= CPSR_F;
8609 if (insn & (1 << 9))
8610 imm = CPSR_A | CPSR_I | CPSR_F;
8611 }
8612 if (insn & (1 << 8)) {
8613 offset |= 0x1f;
8614 imm |= (insn & 0x1f);
8615 }
8616 if (offset) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008617 gen_set_psr_im(s, offset, 0, imm);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008618 }
8619 break;
8620 case 3: /* Special control operations. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008621 ARCH(7);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008622 op = (insn >> 4) & 0xf;
8623 switch (op) {
8624 case 2: /* clrex */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008625 gen_clrex(s);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008626 break;
8627 case 4: /* dsb */
8628 case 5: /* dmb */
8629 case 6: /* isb */
8630 /* These execute as NOPs. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008631 break;
8632 default:
8633 goto illegal_op;
8634 }
8635 break;
8636 case 4: /* bxj */
8637 /* Trivial implementation equivalent to bx. */
8638 tmp = load_reg(s, rn);
8639 gen_bx(s, tmp);
8640 break;
8641 case 5: /* Exception return. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008642 if (IS_USER(s)) {
8643 goto illegal_op;
8644 }
8645 if (rn != 14 || rd != 15) {
8646 goto illegal_op;
8647 }
8648 tmp = load_reg(s, rn);
8649 tcg_gen_subi_i32(tmp, tmp, insn & 0xff);
8650 gen_exception_return(s, tmp);
8651 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008652 case 6: /* mrs cpsr. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008653 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008654 if (IS_M(env)) {
8655 addr = tcg_const_i32(insn & 0xff);
8656 gen_helper_v7m_mrs(tmp, cpu_env, addr);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008657 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008658 } else {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008659 gen_helper_cpsr_read(tmp, cpu_env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008660 }
8661 store_reg(s, rd, tmp);
8662 break;
8663 case 7: /* mrs spsr. */
8664 /* Not accessible in user mode. */
8665 if (IS_USER(s) || IS_M(env))
8666 goto illegal_op;
8667 tmp = load_cpu_field(spsr);
8668 store_reg(s, rd, tmp);
8669 break;
8670 }
8671 }
8672 } else {
8673 /* Conditional branch. */
8674 op = (insn >> 22) & 0xf;
8675 /* Generate a conditional jump to next instruction. */
8676 s->condlabel = gen_new_label();
8677 gen_test_cc(op ^ 1, s->condlabel);
8678 s->condjmp = 1;
8679
8680 /* offset[11:1] = insn[10:0] */
8681 offset = (insn & 0x7ff) << 1;
8682 /* offset[17:12] = insn[21:16]. */
8683 offset |= (insn & 0x003f0000) >> 4;
8684 /* offset[31:20] = insn[26]. */
8685 offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11;
8686 /* offset[18] = insn[13]. */
8687 offset |= (insn & (1 << 13)) << 5;
8688 /* offset[19] = insn[11]. */
8689 offset |= (insn & (1 << 11)) << 8;
8690
8691 /* jump to the offset */
8692 gen_jmp(s, s->pc + offset);
8693 }
8694 } else {
8695 /* Data processing immediate. */
8696 if (insn & (1 << 25)) {
8697 if (insn & (1 << 24)) {
8698 if (insn & (1 << 20))
8699 goto illegal_op;
8700 /* Bitfield/Saturate. */
8701 op = (insn >> 21) & 7;
8702 imm = insn & 0x1f;
8703 shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
8704 if (rn == 15) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008705 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008706 tcg_gen_movi_i32(tmp, 0);
8707 } else {
8708 tmp = load_reg(s, rn);
8709 }
8710 switch (op) {
8711 case 2: /* Signed bitfield extract. */
8712 imm++;
8713 if (shift + imm > 32)
8714 goto illegal_op;
8715 if (imm < 32)
8716 gen_sbfx(tmp, shift, imm);
8717 break;
8718 case 6: /* Unsigned bitfield extract. */
8719 imm++;
8720 if (shift + imm > 32)
8721 goto illegal_op;
8722 if (imm < 32)
8723 gen_ubfx(tmp, shift, (1u << imm) - 1);
8724 break;
8725 case 3: /* Bitfield insert/clear. */
8726 if (imm < shift)
8727 goto illegal_op;
8728 imm = imm + 1 - shift;
8729 if (imm != 32) {
8730 tmp2 = load_reg(s, rd);
8731 gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008732 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008733 }
8734 break;
8735 case 7:
8736 goto illegal_op;
8737 default: /* Saturate. */
8738 if (shift) {
8739 if (op & 1)
8740 tcg_gen_sari_i32(tmp, tmp, shift);
8741 else
8742 tcg_gen_shli_i32(tmp, tmp, shift);
8743 }
8744 tmp2 = tcg_const_i32(imm);
8745 if (op & 4) {
8746 /* Unsigned. */
8747 if ((op & 1) && shift == 0)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008748 gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008749 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008750 gen_helper_usat(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008751 } else {
8752 /* Signed. */
8753 if ((op & 1) && shift == 0)
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008754 gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008755 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02008756 gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008757 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008758 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008759 break;
8760 }
8761 store_reg(s, rd, tmp);
8762 } else {
8763 imm = ((insn & 0x04000000) >> 15)
8764 | ((insn & 0x7000) >> 4) | (insn & 0xff);
8765 if (insn & (1 << 22)) {
8766 /* 16-bit immediate. */
8767 imm |= (insn >> 4) & 0xf000;
8768 if (insn & (1 << 23)) {
8769 /* movt */
8770 tmp = load_reg(s, rd);
8771 tcg_gen_ext16u_i32(tmp, tmp);
8772 tcg_gen_ori_i32(tmp, tmp, imm << 16);
8773 } else {
8774 /* movw */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008775 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008776 tcg_gen_movi_i32(tmp, imm);
8777 }
8778 } else {
8779 /* Add/sub 12-bit immediate. */
8780 if (rn == 15) {
8781 offset = s->pc & ~(uint32_t)3;
8782 if (insn & (1 << 23))
8783 offset -= imm;
8784 else
8785 offset += imm;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008786 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008787 tcg_gen_movi_i32(tmp, offset);
8788 } else {
8789 tmp = load_reg(s, rn);
8790 if (insn & (1 << 23))
8791 tcg_gen_subi_i32(tmp, tmp, imm);
8792 else
8793 tcg_gen_addi_i32(tmp, tmp, imm);
8794 }
8795 }
8796 store_reg(s, rd, tmp);
8797 }
8798 } else {
8799 int shifter_out = 0;
8800 /* modified 12-bit immediate. */
8801 shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12);
8802 imm = (insn & 0xff);
8803 switch (shift) {
8804 case 0: /* XY */
8805 /* Nothing to do. */
8806 break;
8807 case 1: /* 00XY00XY */
8808 imm |= imm << 16;
8809 break;
8810 case 2: /* XY00XY00 */
8811 imm |= imm << 16;
8812 imm <<= 8;
8813 break;
8814 case 3: /* XYXYXYXY */
8815 imm |= imm << 16;
8816 imm |= imm << 8;
8817 break;
8818 default: /* Rotated constant. */
8819 shift = (shift << 1) | (imm >> 7);
8820 imm |= 0x80;
8821 imm = imm << (32 - shift);
8822 shifter_out = 1;
8823 break;
8824 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008825 tmp2 = tcg_temp_new_i32();
8826 tcg_gen_movi_i32(tmp2, imm);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008827 rn = (insn >> 16) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008828 if (rn == 15) {
8829 tmp = tcg_temp_new_i32();
8830 tcg_gen_movi_i32(tmp, 0);
8831 } else {
8832 tmp = load_reg(s, rn);
8833 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008834 op = (insn >> 21) & 0xf;
8835 if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
David 'Digit' Turner52858642011-06-03 13:41:05 +02008836 shifter_out, tmp, tmp2))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008837 goto illegal_op;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008838 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008839 rd = (insn >> 8) & 0xf;
8840 if (rd != 15) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008841 store_reg(s, rd, tmp);
8842 } else {
8843 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008844 }
8845 }
8846 }
8847 break;
8848 case 12: /* Load/store single data item. */
8849 {
8850 int postinc = 0;
8851 int writeback = 0;
8852 int user;
8853 if ((insn & 0x01100000) == 0x01000000) {
8854 if (disas_neon_ls_insn(env, s, insn))
8855 goto illegal_op;
8856 break;
8857 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02008858 op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
8859 if (rs == 15) {
8860 if (!(insn & (1 << 20))) {
8861 goto illegal_op;
8862 }
8863 if (op != 2) {
8864 /* Byte or halfword load space with dest == r15 : memory hints.
8865 * Catch them early so we don't emit pointless addressing code.
8866 * This space is a mix of:
8867 * PLD/PLDW/PLI, which we implement as NOPs (note that unlike
8868 * the ARM encodings, PLDW space doesn't UNDEF for non-v7MP
8869 * cores)
8870 * unallocated hints, which must be treated as NOPs
8871 * UNPREDICTABLE space, which we NOP or UNDEF depending on
8872 * which is easiest for the decoding logic
8873 * Some space which must UNDEF
8874 */
8875 int op1 = (insn >> 23) & 3;
8876 int op2 = (insn >> 6) & 0x3f;
8877 if (op & 2) {
8878 goto illegal_op;
8879 }
8880 if (rn == 15) {
8881 /* UNPREDICTABLE or unallocated hint */
8882 return 0;
8883 }
8884 if (op1 & 1) {
8885 return 0; /* PLD* or unallocated hint */
8886 }
8887 if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) {
8888 return 0; /* PLD* or unallocated hint */
8889 }
8890 /* UNDEF space, or an UNPREDICTABLE */
8891 return 1;
8892 }
8893 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008894 user = IS_USER(s);
8895 if (rn == 15) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008896 addr = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008897 /* PC relative. */
8898 /* s->pc has already been incremented by 4. */
8899 imm = s->pc & 0xfffffffc;
8900 if (insn & (1 << 23))
8901 imm += insn & 0xfff;
8902 else
8903 imm -= insn & 0xfff;
8904 tcg_gen_movi_i32(addr, imm);
8905 } else {
8906 addr = load_reg(s, rn);
8907 if (insn & (1 << 23)) {
8908 /* Positive offset. */
8909 imm = insn & 0xfff;
8910 tcg_gen_addi_i32(addr, addr, imm);
8911 } else {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008912 imm = insn & 0xff;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008913 switch ((insn >> 8) & 0xf) {
8914 case 0x0: /* Shifted Register. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008915 shift = (insn >> 4) & 0xf;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008916 if (shift > 3) {
8917 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008918 goto illegal_op;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008919 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008920 tmp = load_reg(s, rm);
8921 if (shift)
8922 tcg_gen_shli_i32(tmp, tmp, shift);
8923 tcg_gen_add_i32(addr, addr, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02008924 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008925 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008926 case 0xc: /* Negative offset. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008927 tcg_gen_addi_i32(addr, addr, -imm);
8928 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008929 case 0xe: /* User privilege. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008930 tcg_gen_addi_i32(addr, addr, imm);
8931 user = 1;
8932 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008933 case 0x9: /* Post-decrement. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008934 imm = -imm;
8935 /* Fall through. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008936 case 0xb: /* Post-increment. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008937 postinc = 1;
8938 writeback = 1;
8939 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008940 case 0xd: /* Pre-decrement. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008941 imm = -imm;
8942 /* Fall through. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008943 case 0xf: /* Pre-increment. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008944 tcg_gen_addi_i32(addr, addr, imm);
8945 writeback = 1;
8946 break;
8947 default:
David 'Digit' Turner52858642011-06-03 13:41:05 +02008948 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008949 goto illegal_op;
8950 }
8951 }
8952 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008953 if (insn & (1 << 20)) {
8954 /* Load. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02008955 switch (op) {
8956 case 0: tmp = gen_ld8u(addr, user); break;
8957 case 4: tmp = gen_ld8s(addr, user); break;
8958 case 1: tmp = gen_ld16u(addr, user); break;
8959 case 5: tmp = gen_ld16s(addr, user); break;
8960 case 2: tmp = gen_ld32(addr, user); break;
8961 default:
8962 tcg_temp_free_i32(addr);
8963 goto illegal_op;
8964 }
8965 if (rs == 15) {
8966 gen_bx(s, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008967 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008968 store_reg(s, rs, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008969 }
8970 } else {
8971 /* Store. */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008972 tmp = load_reg(s, rs);
8973 switch (op) {
8974 case 0: gen_st8(tmp, addr, user); break;
8975 case 1: gen_st16(tmp, addr, user); break;
8976 case 2: gen_st32(tmp, addr, user); break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02008977 default:
8978 tcg_temp_free_i32(addr);
8979 goto illegal_op;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008980 }
8981 }
8982 if (postinc)
8983 tcg_gen_addi_i32(addr, addr, imm);
8984 if (writeback) {
8985 store_reg(s, rn, addr);
8986 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02008987 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08008988 }
8989 }
8990 break;
8991 default:
8992 goto illegal_op;
8993 }
8994 return 0;
8995illegal_op:
8996 return 1;
8997}
8998
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01008999static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009000{
9001 uint32_t val, insn, op, rm, rn, rd, shift, cond;
9002 int32_t offset;
9003 int i;
9004 TCGv tmp;
9005 TCGv tmp2;
9006 TCGv addr;
9007
Vladimir Chtchetkinea1204592010-04-02 11:03:19 -07009008 if (s->condexec_mask) {
9009 cond = s->condexec_cond;
David 'Digit' Turner52858642011-06-03 13:41:05 +02009010 if (cond != 0x0e) { /* Skip conditional when condition is AL. */
9011 s->condlabel = gen_new_label();
9012 gen_test_cc(cond ^ 1, s->condlabel);
9013 s->condjmp = 1;
9014 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009015 }
9016
David 'Digit' Turnereca7bc22014-03-14 23:58:39 +01009017 insn = cpu_lduw_code(env, s->pc);
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08009018
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009019 s->pc += 2;
9020
9021 switch (insn >> 12) {
9022 case 0: case 1:
David 'Digit' Turner52858642011-06-03 13:41:05 +02009023
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009024 rd = insn & 7;
9025 op = (insn >> 11) & 3;
9026 if (op == 3) {
9027 /* add/subtract */
9028 rn = (insn >> 3) & 7;
David 'Digit' Turner52858642011-06-03 13:41:05 +02009029 tmp = load_reg(s, rn);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009030 if (insn & (1 << 10)) {
9031 /* immediate */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009032 tmp2 = tcg_temp_new_i32();
9033 tcg_gen_movi_i32(tmp2, (insn >> 6) & 7);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009034 } else {
9035 /* reg */
9036 rm = (insn >> 6) & 7;
David 'Digit' Turner52858642011-06-03 13:41:05 +02009037 tmp2 = load_reg(s, rm);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009038 }
9039 if (insn & (1 << 9)) {
9040 if (s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009041 tcg_gen_sub_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009042 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009043 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009044 } else {
9045 if (s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009046 tcg_gen_add_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009047 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009048 gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009049 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009050 tcg_temp_free_i32(tmp2);
9051 store_reg(s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009052 } else {
9053 /* shift immediate */
9054 rm = (insn >> 3) & 7;
9055 shift = (insn >> 6) & 0x1f;
9056 tmp = load_reg(s, rm);
9057 gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0);
9058 if (!s->condexec_mask)
9059 gen_logic_CC(tmp);
9060 store_reg(s, rd, tmp);
9061 }
9062 break;
9063 case 2: case 3:
9064 /* arithmetic large immediate */
9065 op = (insn >> 11) & 3;
9066 rd = (insn >> 8) & 0x7;
David 'Digit' Turner52858642011-06-03 13:41:05 +02009067 if (op == 0) { /* mov */
9068 tmp = tcg_temp_new_i32();
9069 tcg_gen_movi_i32(tmp, insn & 0xff);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009070 if (!s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009071 gen_logic_CC(tmp);
9072 store_reg(s, rd, tmp);
9073 } else {
9074 tmp = load_reg(s, rd);
9075 tmp2 = tcg_temp_new_i32();
9076 tcg_gen_movi_i32(tmp2, insn & 0xff);
9077 switch (op) {
9078 case 1: /* cmp */
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009079 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009080 tcg_temp_free_i32(tmp);
9081 tcg_temp_free_i32(tmp2);
9082 break;
9083 case 2: /* add */
9084 if (s->condexec_mask)
9085 tcg_gen_add_i32(tmp, tmp, tmp2);
9086 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009087 gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009088 tcg_temp_free_i32(tmp2);
9089 store_reg(s, rd, tmp);
9090 break;
9091 case 3: /* sub */
9092 if (s->condexec_mask)
9093 tcg_gen_sub_i32(tmp, tmp, tmp2);
9094 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009095 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009096 tcg_temp_free_i32(tmp2);
9097 store_reg(s, rd, tmp);
9098 break;
9099 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009100 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009101 break;
9102 case 4:
9103 if (insn & (1 << 11)) {
9104 rd = (insn >> 8) & 7;
9105 /* load pc-relative. Bit 1 of PC is ignored. */
9106 val = s->pc + 2 + ((insn & 0xff) * 4);
9107 val &= ~(uint32_t)2;
David 'Digit' Turner52858642011-06-03 13:41:05 +02009108 addr = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009109 tcg_gen_movi_i32(addr, val);
9110 tmp = gen_ld32(addr, IS_USER(s));
David 'Digit' Turner52858642011-06-03 13:41:05 +02009111 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009112 store_reg(s, rd, tmp);
9113 break;
9114 }
9115 if (insn & (1 << 10)) {
9116 /* data processing extended or blx */
9117 rd = (insn & 7) | ((insn >> 4) & 8);
9118 rm = (insn >> 3) & 0xf;
9119 op = (insn >> 8) & 3;
9120 switch (op) {
9121 case 0: /* add */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009122 tmp = load_reg(s, rd);
9123 tmp2 = load_reg(s, rm);
9124 tcg_gen_add_i32(tmp, tmp, tmp2);
9125 tcg_temp_free_i32(tmp2);
9126 store_reg(s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009127 break;
9128 case 1: /* cmp */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009129 tmp = load_reg(s, rd);
9130 tmp2 = load_reg(s, rm);
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009131 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009132 tcg_temp_free_i32(tmp2);
9133 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009134 break;
9135 case 2: /* mov/cpy */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009136 tmp = load_reg(s, rm);
9137 store_reg(s, rd, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009138 break;
9139 case 3:/* branch [and link] exchange thumb register */
9140 tmp = load_reg(s, rm);
9141 if (insn & (1 << 7)) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02009142 ARCH(5);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009143 val = (uint32_t)s->pc | 1;
David 'Digit' Turner52858642011-06-03 13:41:05 +02009144 tmp2 = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009145 tcg_gen_movi_i32(tmp2, val);
9146 store_reg(s, 14, tmp2);
9147 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009148 /* already thumb, no need to check */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009149 gen_bx(s, tmp);
9150 break;
9151 }
9152 break;
9153 }
9154
9155 /* data processing register */
9156 rd = insn & 7;
9157 rm = (insn >> 3) & 7;
9158 op = (insn >> 6) & 0xf;
9159 if (op == 2 || op == 3 || op == 4 || op == 7) {
9160 /* the shift/rotate ops want the operands backwards */
9161 val = rm;
9162 rm = rd;
9163 rd = val;
9164 val = 1;
9165 } else {
9166 val = 0;
9167 }
9168
David 'Digit' Turner52858642011-06-03 13:41:05 +02009169 if (op == 9) { /* neg */
9170 tmp = tcg_temp_new_i32();
9171 tcg_gen_movi_i32(tmp, 0);
9172 } else if (op != 0xf) { /* mvn doesn't read its first operand */
9173 tmp = load_reg(s, rd);
9174 } else {
9175 TCGV_UNUSED(tmp);
9176 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009177
David 'Digit' Turner52858642011-06-03 13:41:05 +02009178 tmp2 = load_reg(s, rm);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009179 switch (op) {
9180 case 0x0: /* and */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009181 tcg_gen_and_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009182 if (!s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009183 gen_logic_CC(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009184 break;
9185 case 0x1: /* eor */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009186 tcg_gen_xor_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009187 if (!s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009188 gen_logic_CC(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009189 break;
9190 case 0x2: /* lsl */
9191 if (s->condexec_mask) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02009192 gen_helper_shl(tmp2, tmp2, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009193 } else {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009194 gen_helper_shl_cc(tmp2, cpu_env, tmp2, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009195 gen_logic_CC(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009196 }
9197 break;
9198 case 0x3: /* lsr */
9199 if (s->condexec_mask) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02009200 gen_helper_shr(tmp2, tmp2, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009201 } else {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009202 gen_helper_shr_cc(tmp2, cpu_env, tmp2, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009203 gen_logic_CC(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009204 }
9205 break;
9206 case 0x4: /* asr */
9207 if (s->condexec_mask) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02009208 gen_helper_sar(tmp2, tmp2, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009209 } else {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009210 gen_helper_sar_cc(tmp2, cpu_env, tmp2, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009211 gen_logic_CC(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009212 }
9213 break;
9214 case 0x5: /* adc */
9215 if (s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009216 gen_adc(tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009217 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009218 gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009219 break;
9220 case 0x6: /* sbc */
9221 if (s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009222 gen_sub_carry(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009223 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009224 gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009225 break;
9226 case 0x7: /* ror */
9227 if (s->condexec_mask) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02009228 tcg_gen_andi_i32(tmp, tmp, 0x1f);
9229 tcg_gen_rotr_i32(tmp2, tmp2, tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009230 } else {
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009231 gen_helper_ror_cc(tmp2, cpu_env, tmp2, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009232 gen_logic_CC(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009233 }
9234 break;
9235 case 0x8: /* tst */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009236 tcg_gen_and_i32(tmp, tmp, tmp2);
9237 gen_logic_CC(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009238 rd = 16;
9239 break;
9240 case 0x9: /* neg */
9241 if (s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009242 tcg_gen_neg_i32(tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009243 else
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009244 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009245 break;
9246 case 0xa: /* cmp */
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009247 gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009248 rd = 16;
9249 break;
9250 case 0xb: /* cmn */
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009251 gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009252 rd = 16;
9253 break;
9254 case 0xc: /* orr */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009255 tcg_gen_or_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009256 if (!s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009257 gen_logic_CC(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009258 break;
9259 case 0xd: /* mul */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009260 tcg_gen_mul_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009261 if (!s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009262 gen_logic_CC(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009263 break;
9264 case 0xe: /* bic */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009265 tcg_gen_andc_i32(tmp, tmp, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009266 if (!s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009267 gen_logic_CC(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009268 break;
9269 case 0xf: /* mvn */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009270 tcg_gen_not_i32(tmp2, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009271 if (!s->condexec_mask)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009272 gen_logic_CC(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009273 val = 1;
9274 rm = rd;
9275 break;
9276 }
9277 if (rd != 16) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02009278 if (val) {
9279 store_reg(s, rm, tmp2);
9280 if (op != 0xf)
9281 tcg_temp_free_i32(tmp);
9282 } else {
9283 store_reg(s, rd, tmp);
9284 tcg_temp_free_i32(tmp2);
9285 }
9286 } else {
9287 tcg_temp_free_i32(tmp);
9288 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009289 }
9290 break;
9291
9292 case 5:
9293 /* load/store register offset. */
9294 rd = insn & 7;
9295 rn = (insn >> 3) & 7;
9296 rm = (insn >> 6) & 7;
9297 op = (insn >> 9) & 7;
9298 addr = load_reg(s, rn);
9299 tmp = load_reg(s, rm);
9300 tcg_gen_add_i32(addr, addr, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009301 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009302
9303 if (op < 3) /* store */
9304 tmp = load_reg(s, rd);
9305
9306 switch (op) {
9307 case 0: /* str */
9308 gen_st32(tmp, addr, IS_USER(s));
9309 break;
9310 case 1: /* strh */
9311 gen_st16(tmp, addr, IS_USER(s));
9312 break;
9313 case 2: /* strb */
9314 gen_st8(tmp, addr, IS_USER(s));
9315 break;
9316 case 3: /* ldrsb */
9317 tmp = gen_ld8s(addr, IS_USER(s));
9318 break;
9319 case 4: /* ldr */
9320 tmp = gen_ld32(addr, IS_USER(s));
9321 break;
9322 case 5: /* ldrh */
9323 tmp = gen_ld16u(addr, IS_USER(s));
9324 break;
9325 case 6: /* ldrb */
9326 tmp = gen_ld8u(addr, IS_USER(s));
9327 break;
9328 case 7: /* ldrsh */
9329 tmp = gen_ld16s(addr, IS_USER(s));
9330 break;
9331 }
9332 if (op >= 3) /* load */
9333 store_reg(s, rd, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009334 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009335 break;
9336
9337 case 6:
9338 /* load/store word immediate offset */
9339 rd = insn & 7;
9340 rn = (insn >> 3) & 7;
9341 addr = load_reg(s, rn);
9342 val = (insn >> 4) & 0x7c;
9343 tcg_gen_addi_i32(addr, addr, val);
9344
9345 if (insn & (1 << 11)) {
9346 /* load */
9347 tmp = gen_ld32(addr, IS_USER(s));
9348 store_reg(s, rd, tmp);
9349 } else {
9350 /* store */
9351 tmp = load_reg(s, rd);
9352 gen_st32(tmp, addr, IS_USER(s));
9353 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009354 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009355 break;
9356
9357 case 7:
9358 /* load/store byte immediate offset */
9359 rd = insn & 7;
9360 rn = (insn >> 3) & 7;
9361 addr = load_reg(s, rn);
9362 val = (insn >> 6) & 0x1f;
9363 tcg_gen_addi_i32(addr, addr, val);
9364
9365 if (insn & (1 << 11)) {
9366 /* load */
9367 tmp = gen_ld8u(addr, IS_USER(s));
9368 store_reg(s, rd, tmp);
9369 } else {
9370 /* store */
9371 tmp = load_reg(s, rd);
9372 gen_st8(tmp, addr, IS_USER(s));
9373 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009374 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009375 break;
9376
9377 case 8:
9378 /* load/store halfword immediate offset */
9379 rd = insn & 7;
9380 rn = (insn >> 3) & 7;
9381 addr = load_reg(s, rn);
9382 val = (insn >> 5) & 0x3e;
9383 tcg_gen_addi_i32(addr, addr, val);
9384
9385 if (insn & (1 << 11)) {
9386 /* load */
9387 tmp = gen_ld16u(addr, IS_USER(s));
9388 store_reg(s, rd, tmp);
9389 } else {
9390 /* store */
9391 tmp = load_reg(s, rd);
9392 gen_st16(tmp, addr, IS_USER(s));
9393 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009394 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009395 break;
9396
9397 case 9:
9398 /* load/store from stack */
9399 rd = (insn >> 8) & 7;
9400 addr = load_reg(s, 13);
9401 val = (insn & 0xff) * 4;
9402 tcg_gen_addi_i32(addr, addr, val);
9403
9404 if (insn & (1 << 11)) {
9405 /* load */
9406 tmp = gen_ld32(addr, IS_USER(s));
9407 store_reg(s, rd, tmp);
9408 } else {
9409 /* store */
9410 tmp = load_reg(s, rd);
9411 gen_st32(tmp, addr, IS_USER(s));
9412 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009413 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009414 break;
9415
9416 case 10:
9417 /* add to high reg */
9418 rd = (insn >> 8) & 7;
9419 if (insn & (1 << 11)) {
9420 /* SP */
9421 tmp = load_reg(s, 13);
9422 } else {
9423 /* PC. bit 1 is ignored. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009424 tmp = tcg_temp_new_i32();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009425 tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
9426 }
9427 val = (insn & 0xff) * 4;
9428 tcg_gen_addi_i32(tmp, tmp, val);
9429 store_reg(s, rd, tmp);
9430 break;
9431
9432 case 11:
9433 /* misc */
9434 op = (insn >> 8) & 0xf;
9435 switch (op) {
9436 case 0:
9437 /* adjust stack pointer */
9438 tmp = load_reg(s, 13);
9439 val = (insn & 0x7f) * 4;
9440 if (insn & (1 << 7))
9441 val = -(int32_t)val;
9442 tcg_gen_addi_i32(tmp, tmp, val);
9443 store_reg(s, 13, tmp);
9444 break;
9445
9446 case 2: /* sign/zero extend. */
9447 ARCH(6);
9448 rd = insn & 7;
9449 rm = (insn >> 3) & 7;
9450 tmp = load_reg(s, rm);
9451 switch ((insn >> 6) & 3) {
9452 case 0: gen_sxth(tmp); break;
9453 case 1: gen_sxtb(tmp); break;
9454 case 2: gen_uxth(tmp); break;
9455 case 3: gen_uxtb(tmp); break;
9456 }
9457 store_reg(s, rd, tmp);
9458 break;
9459 case 4: case 5: case 0xc: case 0xd:
9460 /* push/pop */
9461 addr = load_reg(s, 13);
9462 if (insn & (1 << 8))
9463 offset = 4;
9464 else
9465 offset = 0;
9466 for (i = 0; i < 8; i++) {
9467 if (insn & (1 << i))
9468 offset += 4;
9469 }
9470 if ((insn & (1 << 11)) == 0) {
9471 tcg_gen_addi_i32(addr, addr, -offset);
9472 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009473 tmp2 = tcg_const_i32(4);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009474 for (i = 0; i < 8; i++) {
9475 if (insn & (1 << i)) {
9476 if (insn & (1 << 11)) {
9477 /* pop */
9478 tmp = gen_ld32(addr, IS_USER(s));
9479 store_reg(s, i, tmp);
9480 } else {
9481 /* push */
9482 tmp = load_reg(s, i);
9483 gen_st32(tmp, addr, IS_USER(s));
9484 }
9485 /* advance to the next address. */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009486 tcg_gen_add_i32(addr, addr, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009487 }
9488 }
9489 TCGV_UNUSED(tmp);
9490 if (insn & (1 << 8)) {
9491 if (insn & (1 << 11)) {
9492 /* pop pc */
9493 tmp = gen_ld32(addr, IS_USER(s));
9494 /* don't set the pc until the rest of the instruction
9495 has completed */
9496 } else {
9497 /* push lr */
9498 tmp = load_reg(s, 14);
9499 gen_st32(tmp, addr, IS_USER(s));
9500 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009501 tcg_gen_add_i32(addr, addr, tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009502 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009503 tcg_temp_free_i32(tmp2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009504 if ((insn & (1 << 11)) == 0) {
9505 tcg_gen_addi_i32(addr, addr, -offset);
9506 }
9507 /* write back the new stack pointer */
9508 store_reg(s, 13, addr);
9509 /* set the new PC value */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009510 if ((insn & 0x0900) == 0x0900) {
9511 store_reg_from_load(env, s, 15, tmp);
9512 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009513 break;
9514
9515 case 1: case 3: case 9: case 11: /* czb */
9516 rm = insn & 7;
9517 tmp = load_reg(s, rm);
9518 s->condlabel = gen_new_label();
9519 s->condjmp = 1;
9520 if (insn & (1 << 11))
9521 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
9522 else
9523 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009524 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009525 offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3;
9526 val = (uint32_t)s->pc + 2;
9527 val += offset;
9528 gen_jmp(s, val);
9529 break;
9530
9531 case 15: /* IT, nop-hint. */
9532 if ((insn & 0xf) == 0) {
9533 gen_nop_hint(s, (insn >> 4) & 0xf);
9534 break;
9535 }
9536 /* If Then. */
Vladimir Chtchetkinea1204592010-04-02 11:03:19 -07009537 s->condexec_cond = (insn >> 4) & 0xe;
9538 s->condexec_mask = insn & 0x1f;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009539 /* No actual code generated for this insn, just setup state. */
9540 break;
9541
9542 case 0xe: /* bkpt */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009543 ARCH(5);
9544 gen_exception_insn(s, 2, EXCP_BKPT);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009545 break;
9546
9547 case 0xa: /* rev */
9548 ARCH(6);
9549 rn = (insn >> 3) & 0x7;
9550 rd = insn & 0x7;
9551 tmp = load_reg(s, rn);
9552 switch ((insn >> 6) & 3) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07009553 case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009554 case 1: gen_rev16(tmp); break;
9555 case 3: gen_revsh(tmp); break;
9556 default: goto illegal_op;
9557 }
9558 store_reg(s, rd, tmp);
9559 break;
9560
9561 case 6: /* cps */
9562 ARCH(6);
9563 if (IS_USER(s))
9564 break;
9565 if (IS_M(env)) {
9566 tmp = tcg_const_i32((insn & (1 << 4)) != 0);
9567 /* PRIMASK */
9568 if (insn & 1) {
9569 addr = tcg_const_i32(16);
9570 gen_helper_v7m_msr(cpu_env, addr, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009571 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009572 }
9573 /* FAULTMASK */
9574 if (insn & 2) {
9575 addr = tcg_const_i32(17);
9576 gen_helper_v7m_msr(cpu_env, addr, tmp);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009577 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009578 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009579 tcg_temp_free_i32(tmp);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009580 gen_lookup_tb(s);
9581 } else {
9582 if (insn & (1 << 4))
9583 shift = CPSR_A | CPSR_I | CPSR_F;
9584 else
9585 shift = 0;
David 'Digit' Turner52858642011-06-03 13:41:05 +02009586 gen_set_psr_im(s, ((insn & 7) << 6), 0, shift);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009587 }
9588 break;
9589
9590 default:
9591 goto undef;
9592 }
9593 break;
9594
9595 case 12:
David 'Digit' Turner52858642011-06-03 13:41:05 +02009596 {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009597 /* load/store multiple */
David 'Digit' Turner52858642011-06-03 13:41:05 +02009598 TCGv loaded_var;
9599 TCGV_UNUSED(loaded_var);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009600 rn = (insn >> 8) & 0x7;
9601 addr = load_reg(s, rn);
9602 for (i = 0; i < 8; i++) {
9603 if (insn & (1 << i)) {
9604 if (insn & (1 << 11)) {
9605 /* load */
9606 tmp = gen_ld32(addr, IS_USER(s));
David 'Digit' Turner52858642011-06-03 13:41:05 +02009607 if (i == rn) {
9608 loaded_var = tmp;
9609 } else {
9610 store_reg(s, i, tmp);
9611 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009612 } else {
9613 /* store */
9614 tmp = load_reg(s, i);
9615 gen_st32(tmp, addr, IS_USER(s));
9616 }
9617 /* advance to the next address */
9618 tcg_gen_addi_i32(addr, addr, 4);
9619 }
9620 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009621 if ((insn & (1 << rn)) == 0) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02009622 /* base reg not in list: base register writeback */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009623 store_reg(s, rn, addr);
9624 } else {
David 'Digit' Turner52858642011-06-03 13:41:05 +02009625 /* base reg in list: if load, complete it now */
9626 if (insn & (1 << 11)) {
9627 store_reg(s, rn, loaded_var);
9628 }
9629 tcg_temp_free_i32(addr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009630 }
9631 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02009632 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009633 case 13:
9634 /* conditional branch or swi */
9635 cond = (insn >> 8) & 0xf;
9636 if (cond == 0xe)
9637 goto undef;
9638
9639 if (cond == 0xf) {
9640 /* swi */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009641 gen_set_pc_im(s->pc);
9642 s->is_jmp = DISAS_SWI;
9643 break;
9644 }
9645 /* generate a conditional jump to next instruction */
9646 s->condlabel = gen_new_label();
9647 gen_test_cc(cond ^ 1, s->condlabel);
9648 s->condjmp = 1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009649
9650 /* jump to the offset */
9651 val = (uint32_t)s->pc + 2;
9652 offset = ((int32_t)insn << 24) >> 24;
9653 val += offset << 1;
9654 gen_jmp(s, val);
9655 break;
9656
9657 case 14:
9658 if (insn & (1 << 11)) {
9659 if (disas_thumb2_insn(env, s, insn))
9660 goto undef32;
9661 break;
9662 }
9663 /* unconditional branch */
9664 val = (uint32_t)s->pc;
9665 offset = ((int32_t)insn << 21) >> 21;
9666 val += (offset << 1) + 2;
9667 gen_jmp(s, val);
9668 break;
9669
9670 case 15:
9671 if (disas_thumb2_insn(env, s, insn))
9672 goto undef32;
9673 break;
9674 }
9675 return;
9676undef32:
David 'Digit' Turner52858642011-06-03 13:41:05 +02009677 gen_exception_insn(s, 4, EXCP_UDEF);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009678 return;
9679illegal_op:
9680undef:
David 'Digit' Turner52858642011-06-03 13:41:05 +02009681 gen_exception_insn(s, 2, EXCP_UDEF);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009682}
9683
9684/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
9685 basic block 'tb'. If search_pc is TRUE, also generate PC
9686 information for each intermediate instruction. */
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01009687static inline void gen_intermediate_code_internal(CPUARMState *env,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009688 TranslationBlock *tb,
9689 int search_pc)
9690{
9691 DisasContext dc1, *dc = &dc1;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07009692 CPUBreakpoint *bp;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009693 uint16_t *gen_opc_end;
9694 int j, lj;
9695 target_ulong pc_start;
9696 uint32_t next_page_start;
9697 int num_insns;
9698 int max_insns;
9699
9700 /* generate intermediate code */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009701 pc_start = tb->pc;
9702
9703 dc->tb = tb;
9704
David 'Digit' Turner975bba82014-02-17 23:33:29 +01009705 gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009706
9707 dc->is_jmp = DISAS_NEXT;
9708 dc->pc = pc_start;
David 'Digit' Turnerfed223d2014-03-24 17:42:47 +01009709 dc->singlestep_enabled = ENV_GET_CPU(env)->singlestep_enabled;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009710 dc->condjmp = 0;
David 'Digit' Turner52858642011-06-03 13:41:05 +02009711 dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
9712 dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
9713 dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009714#if !defined(CONFIG_USER_ONLY)
David 'Digit' Turner52858642011-06-03 13:41:05 +02009715 dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009716#endif
David 'Digit' Turner52858642011-06-03 13:41:05 +02009717 dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
9718 dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
9719 dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07009720 cpu_F0s = tcg_temp_new_i32();
9721 cpu_F1s = tcg_temp_new_i32();
9722 cpu_F0d = tcg_temp_new_i64();
9723 cpu_F1d = tcg_temp_new_i64();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009724 cpu_V0 = cpu_F0d;
9725 cpu_V1 = cpu_F1d;
9726 /* FIXME: cpu_M0 can probably be the same as cpu_V0. */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07009727 cpu_M0 = tcg_temp_new_i64();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009728 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
9729 lj = -1;
9730 num_insns = 0;
9731 max_insns = tb->cflags & CF_COUNT_MASK;
9732 if (max_insns == 0)
9733 max_insns = CF_COUNT_MASK;
9734
9735 gen_icount_start();
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009736
David 'Digit' Turner52858642011-06-03 13:41:05 +02009737 tcg_clear_temp_count();
9738
9739 /* A note on handling of the condexec (IT) bits:
9740 *
9741 * We want to avoid the overhead of having to write the updated condexec
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01009742 * bits back to the CPUARMState for every instruction in an IT block. So:
David 'Digit' Turner52858642011-06-03 13:41:05 +02009743 * (1) if the condexec bits are not already zero then we write
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01009744 * zero back into the CPUARMState now. This avoids complications trying
David 'Digit' Turner52858642011-06-03 13:41:05 +02009745 * to do it at the end of the block. (For example if we don't do this
9746 * it's hard to identify whether we can safely skip writing condexec
9747 * at the end of the TB, which we definitely want to do for the case
9748 * where a TB doesn't do anything with the IT state at all.)
9749 * (2) if we are going to leave the TB then we call gen_set_condexec()
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01009750 * which will write the correct value into CPUARMState if zero is wrong.
David 'Digit' Turner52858642011-06-03 13:41:05 +02009751 * This is done both for leaving the TB at the end, and for leaving
9752 * it because of an exception we know will happen, which is done in
9753 * gen_exception_insn(). The latter is necessary because we need to
9754 * leave the TB with the PC/IT state just prior to execution of the
9755 * instruction which caused the exception.
9756 * (3) if we leave the TB unexpectedly (eg a data abort on a load)
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01009757 * then the CPUARMState will be wrong and we need to reset it.
David 'Digit' Turner52858642011-06-03 13:41:05 +02009758 * This is handled in the same way as restoration of the
9759 * PC in these situations: we will be called again with search_pc=1
9760 * and generate a mapping of the condexec bits for each PC in
9761 * gen_opc_condexec_bits[]. restore_state_to_opc() then uses
9762 * this to restore the condexec bits.
9763 *
9764 * Note that there are no instructions which can read the condexec
9765 * bits, and none which can write non-static values to them, so
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01009766 * we don't need to care about whether CPUARMState is correct in the
David 'Digit' Turner52858642011-06-03 13:41:05 +02009767 * middle of a TB.
9768 */
9769
9770 /* Reset the conditional execution bits immediately. This avoids
9771 complications trying to do it at the end of the block. */
9772 if (dc->condexec_mask || dc->condexec_cond)
9773 {
9774 TCGv tmp = tcg_temp_new_i32();
9775 tcg_gen_movi_i32(tmp, 0);
9776 store_cpu_field(tmp, condexec_bits);
9777 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009778 do {
9779#ifdef CONFIG_USER_ONLY
9780 /* Intercept jump to the magic kernel page. */
9781 if (dc->pc >= 0xffff0000) {
9782 /* We always get here via a jump, so know we are not in a
9783 conditional execution block. */
9784 gen_exception(EXCP_KERNEL_TRAP);
9785 dc->is_jmp = DISAS_UPDATE;
9786 break;
9787 }
9788#else
9789 if (dc->pc >= 0xfffffff0 && IS_M(env)) {
9790 /* We always get here via a jump, so know we are not in a
9791 conditional execution block. */
9792 gen_exception(EXCP_EXCEPTION_EXIT);
9793 dc->is_jmp = DISAS_UPDATE;
9794 break;
9795 }
9796#endif
9797
David 'Digit' Turnera5d41202010-05-10 18:37:10 -07009798 if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
9799 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07009800 if (bp->pc == dc->pc) {
David 'Digit' Turner52858642011-06-03 13:41:05 +02009801 gen_exception_insn(dc, 0, EXCP_DEBUG);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009802 /* Advance PC so that clearing the breakpoint will
9803 invalidate this TB. */
9804 dc->pc += 2;
9805 goto done_generating;
9806 break;
9807 }
9808 }
9809 }
Vladimir Chtchetkine5389aa12010-02-16 10:38:35 -08009810
David 'Digit' Turnerc3b504f2014-07-04 11:45:39 +02009811 if (search_pc) {
9812 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
9813 if (lj < j) {
9814 lj++;
9815 while (lj < j)
9816 tcg_ctx.gen_opc_instr_start[lj++] = 0;
9817 }
9818 tcg_ctx.gen_opc_pc[lj] = dc->pc;
9819 gen_opc_condexec_bits[lj] = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1);
9820 tcg_ctx.gen_opc_instr_start[lj] = 1;
9821 tcg_ctx.gen_opc_icount[lj] = num_insns;
9822 }
9823
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009824 if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
9825 gen_io_start();
9826
David 'Digit' Turner52858642011-06-03 13:41:05 +02009827 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
9828 tcg_gen_debug_insn_start(dc->pc);
9829 }
9830
9831 if (dc->thumb) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009832 disas_thumb_insn(env, dc);
9833 if (dc->condexec_mask) {
Vladimir Chtchetkinea1204592010-04-02 11:03:19 -07009834 dc->condexec_cond = (dc->condexec_cond & 0xe)
9835 | ((dc->condexec_mask >> 4) & 1);
9836 dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
9837 if (dc->condexec_mask == 0) {
9838 dc->condexec_cond = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009839 }
9840 }
9841 } else {
9842 disas_arm_insn(env, dc);
9843 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009844
9845 if (dc->condjmp && !dc->is_jmp) {
9846 gen_set_label(dc->condlabel);
9847 dc->condjmp = 0;
9848 }
David 'Digit' Turner52858642011-06-03 13:41:05 +02009849
9850 if (tcg_check_temp_count()) {
9851 fprintf(stderr, "TCG temporary leak before %08x\n", dc->pc);
9852 }
9853
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07009854 /* Translation stops when a conditional branch is encountered.
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009855 * Otherwise the subsequent code could get translated several times.
9856 * Also stop translation when a page boundary is reached. This
9857 * ensures prefetch aborts occur at the right place. */
9858 num_insns ++;
David 'Digit' Turner975bba82014-02-17 23:33:29 +01009859 } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
David 'Digit' Turnerfed223d2014-03-24 17:42:47 +01009860 !ENV_GET_CPU(env)->singlestep_enabled &&
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07009861 !singlestep &&
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009862 dc->pc < next_page_start &&
9863 num_insns < max_insns);
9864
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009865 if (tb->cflags & CF_LAST_IO) {
9866 if (dc->condjmp) {
9867 /* FIXME: This can theoretically happen with self-modifying
9868 code. */
9869 cpu_abort(env, "IO on conditional branch instruction");
9870 }
9871 gen_io_end();
9872 }
9873
9874 /* At this stage dc->condjmp will only be set when the skipped
9875 instruction was a conditional branch or trap, and the PC has
9876 already been written. */
David 'Digit' Turnerfed223d2014-03-24 17:42:47 +01009877 if (unlikely(ENV_GET_CPU(env)->singlestep_enabled)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009878 /* Make sure the pc is updated, and raise a debug exception. */
9879 if (dc->condjmp) {
9880 gen_set_condexec(dc);
9881 if (dc->is_jmp == DISAS_SWI) {
9882 gen_exception(EXCP_SWI);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009883 } else if (dc->is_jmp == DISAS_SMC) {
9884 gen_exception(EXCP_SMC);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009885 } else {
9886 gen_exception(EXCP_DEBUG);
9887 }
9888 gen_set_label(dc->condlabel);
9889 }
9890 if (dc->condjmp || !dc->is_jmp) {
9891 gen_set_pc_im(dc->pc);
9892 dc->condjmp = 0;
9893 }
9894 gen_set_condexec(dc);
9895 if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
9896 gen_exception(EXCP_SWI);
David 'Digit' Turner52858642011-06-03 13:41:05 +02009897 } else if (dc->is_jmp == DISAS_SMC && !dc->condjmp) {
9898 gen_exception(EXCP_SMC);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009899 } else {
9900 /* FIXME: Single stepping a WFI insn will not halt
9901 the CPU. */
9902 gen_exception(EXCP_DEBUG);
9903 }
9904 } else {
9905 /* While branches must always occur at the end of an IT block,
9906 there are a few other things that can cause us to terminate
9907 the TB in the middel of an IT block:
9908 - Exception generating instructions (bkpt, swi, undefined).
9909 - Page boundaries.
9910 - Hardware watchpoints.
9911 Hardware breakpoints have already been handled and skip this code.
9912 */
9913 gen_set_condexec(dc);
9914 switch(dc->is_jmp) {
9915 case DISAS_NEXT:
9916 gen_goto_tb(dc, 1, dc->pc);
9917 break;
9918 default:
9919 case DISAS_JUMP:
9920 case DISAS_UPDATE:
9921 /* indicate that the hash table must be used to find the next TB */
9922 tcg_gen_exit_tb(0);
9923 break;
9924 case DISAS_TB_JUMP:
9925 /* nothing more to generate */
9926 break;
9927 case DISAS_WFI:
David 'Digit' Turner0b4c9e82014-04-03 00:37:18 +02009928 gen_helper_wfi(cpu_env);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009929 break;
9930 case DISAS_SWI:
9931 gen_exception(EXCP_SWI);
9932 break;
David 'Digit' Turner52858642011-06-03 13:41:05 +02009933 case DISAS_SMC:
9934 gen_exception(EXCP_SMC);
9935 break;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009936 }
9937 if (dc->condjmp) {
9938 gen_set_label(dc->condlabel);
9939 gen_set_condexec(dc);
9940 gen_goto_tb(dc, 1, dc->pc);
9941 dc->condjmp = 0;
9942 }
9943 }
9944
9945done_generating:
9946 gen_icount_end(tb, num_insns);
David 'Digit' Turner975bba82014-02-17 23:33:29 +01009947 *tcg_ctx.gen_opc_ptr = INDEX_op_end;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009948
9949#ifdef DEBUG_DISAS
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07009950 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
9951 qemu_log("----------------\n");
9952 qemu_log("IN: %s\n", lookup_symbol(pc_start));
David 'Digit' Turner0dc43a92014-01-16 15:43:33 +01009953 log_target_disas(env, pc_start, dc->pc - pc_start, dc->thumb);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07009954 qemu_log("\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009955 }
9956#endif
9957 if (search_pc) {
David 'Digit' Turner975bba82014-02-17 23:33:29 +01009958 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009959 lj++;
9960 while (lj <= j)
David 'Digit' Turner975bba82014-02-17 23:33:29 +01009961 tcg_ctx.gen_opc_instr_start[lj++] = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009962 } else {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009963 tb->size = dc->pc - pc_start;
9964 tb->icount = num_insns;
9965 }
9966}
9967
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01009968void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009969{
9970 gen_intermediate_code_internal(env, tb, 0);
9971}
9972
David 'Digit' Turnere2678e12014-01-16 15:56:43 +01009973void gen_intermediate_code_pc(CPUARMState *env, TranslationBlock *tb)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009974{
9975 gen_intermediate_code_internal(env, tb, 1);
9976}
9977
9978static const char *cpu_mode_names[16] = {
9979 "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
9980 "???", "???", "???", "und", "???", "???", "???", "sys"
9981};
9982
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +01009983void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009984 int flags)
9985{
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +01009986 CPUARMState *env = cpu->env_ptr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08009987 int i;
9988#if 0
9989 union {
9990 uint32_t i;
9991 float s;
9992 } s0, s1;
9993 CPU_DoubleU d;
9994 /* ??? This assumes float64 and double have the same layout.
9995 Oh well, it's only debug dumps. */
9996 union {
9997 float64 f64;
9998 double d;
9999 } d0;
10000#endif
10001 uint32_t psr;
10002
10003 for(i=0;i<16;i++) {
10004 cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
10005 if ((i % 4) == 3)
10006 cpu_fprintf(f, "\n");
10007 else
10008 cpu_fprintf(f, " ");
10009 }
10010 psr = cpsr_read(env);
10011 cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
10012 psr,
10013 psr & (1 << 31) ? 'N' : '-',
10014 psr & (1 << 30) ? 'Z' : '-',
10015 psr & (1 << 29) ? 'C' : '-',
10016 psr & (1 << 28) ? 'V' : '-',
10017 psr & CPSR_T ? 'T' : 'A',
10018 cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
10019
10020#if 0
10021 for (i = 0; i < 16; i++) {
10022 d.d = env->vfp.regs[i];
10023 s0.i = d.l.lower;
10024 s1.i = d.l.upper;
10025 d0.f64 = d.d;
10026 cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
10027 i * 2, (int)s0.i, s0.s,
10028 i * 2 + 1, (int)s1.i, s1.s,
10029 i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
10030 d0.d);
10031 }
10032 cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
10033#endif
10034}
10035
David 'Digit' Turnere2678e12014-01-16 15:56:43 +010010036void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080010037{
David 'Digit' Turner975bba82014-02-17 23:33:29 +010010038 env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
David 'Digit' Turner86b1fb02014-03-21 15:20:21 +010010039 env->condexec_bits = gen_opc_condexec_bits[pc_pos];
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080010040}