blob: 280bfca62bab1bc6b290e2abefaed02f393f812c [file] [log] [blame]
bellard2c0262a2003-09-30 20:34:21 +00001/*
2 * ARM translation
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard2c0262a2003-09-30 20:34:21 +00004 * Copyright (c) 2003 Fabrice Bellard
pbrook9ee6e8b2007-11-11 00:04:49 +00005 * Copyright (c) 2005-2007 CodeSourcery
balrog18c9b562007-04-30 02:02:17 +00006 * Copyright (c) 2007 OpenedHand, Ltd.
bellard2c0262a2003-09-30 20:34:21 +00007 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000019 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellard2c0262a2003-09-30 20:34:21 +000020 */
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"
bellard2c0262a2003-09-30 20:34:21 +000028#include "disas.h"
bellard57fec1f2008-02-01 10:50:11 +000029#include "tcg-op.h"
blueswir179383c92008-08-30 09:51:20 +000030#include "qemu-log.h"
pbrook1497c962008-03-31 03:45:50 +000031
Lluís7b592202011-04-13 18:38:24 +020032#include "helper.h"
pbrook1497c962008-03-31 03:45:50 +000033#define GEN_HELPER 1
Lluís7b592202011-04-13 18:38:24 +020034#include "helper.h"
bellard2c0262a2003-09-30 20:34:21 +000035
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +040036#define ENABLE_ARCH_4T arm_feature(env, ARM_FEATURE_V4T)
37#define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5)
38/* currently all emulated v5 cores are also v5TE, so don't bother */
39#define ENABLE_ARCH_5TE arm_feature(env, ARM_FEATURE_V5)
pbrook9ee6e8b2007-11-11 00:04:49 +000040#define ENABLE_ARCH_5J 0
41#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6)
42#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K)
43#define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2)
44#define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7)
bellardb5ff1b32005-11-26 10:38:39 +000045
pbrook86753402008-10-22 20:35:54 +000046#define ARCH(x) do { if (!ENABLE_ARCH_##x) goto illegal_op; } while(0)
bellardb5ff1b32005-11-26 10:38:39 +000047
bellard2c0262a2003-09-30 20:34:21 +000048/* internal defines */
49typedef struct DisasContext {
bellard0fa85d42005-01-03 23:43:32 +000050 target_ulong pc;
bellard2c0262a2003-09-30 20:34:21 +000051 int is_jmp;
bellarde50e6a22005-04-26 20:36:11 +000052 /* Nonzero if this instruction has been conditionally skipped. */
53 int condjmp;
54 /* The label that will be jumped to when the instruction is skipped. */
55 int condlabel;
pbrook9ee6e8b2007-11-11 00:04:49 +000056 /* Thumb-2 condtional execution bits. */
57 int condexec_mask;
58 int condexec_cond;
bellard2c0262a2003-09-30 20:34:21 +000059 struct TranslationBlock *tb;
bellard8aaca4c2005-04-23 18:27:52 +000060 int singlestep_enabled;
bellard5899f382005-04-27 20:25:20 +000061 int thumb;
bellardb5ff1b32005-11-26 10:38:39 +000062#if !defined(CONFIG_USER_ONLY)
63 int user;
64#endif
Peter Maydell5df8bac2011-01-14 20:39:19 +010065 int vfp_enabled;
Peter Maydell69d1fc22011-01-14 20:39:19 +010066 int vec_len;
67 int vec_stride;
bellard2c0262a2003-09-30 20:34:21 +000068} DisasContext;
69
Peter Maydelle12ce782011-01-14 20:39:19 +010070static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
71
bellardb5ff1b32005-11-26 10:38:39 +000072#if defined(CONFIG_USER_ONLY)
73#define IS_USER(s) 1
74#else
75#define IS_USER(s) (s->user)
76#endif
77
pbrook9ee6e8b2007-11-11 00:04:49 +000078/* These instructions trap after executing, so defer them until after the
79 conditional executions state has been updated. */
80#define DISAS_WFI 4
81#define DISAS_SWI 5
bellard2c0262a2003-09-30 20:34:21 +000082
pbrooka7812ae2008-11-17 14:43:54 +000083static TCGv_ptr cpu_env;
pbrookad694712008-03-31 03:48:30 +000084/* We reuse the same 64-bit temporaries for efficiency. */
pbrooka7812ae2008-11-17 14:43:54 +000085static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
Filip Navara155c3ea2009-10-15 12:00:41 +020086static TCGv_i32 cpu_R[16];
Paul Brook426f5ab2009-11-22 21:35:13 +000087static TCGv_i32 cpu_exclusive_addr;
88static TCGv_i32 cpu_exclusive_val;
89static TCGv_i32 cpu_exclusive_high;
90#ifdef CONFIG_USER_ONLY
91static TCGv_i32 cpu_exclusive_test;
92static TCGv_i32 cpu_exclusive_info;
93#endif
pbrookad694712008-03-31 03:48:30 +000094
pbrookb26eefb2008-03-31 03:44:26 +000095/* FIXME: These should be removed. */
pbrooka7812ae2008-11-17 14:43:54 +000096static TCGv cpu_F0s, cpu_F1s;
97static TCGv_i64 cpu_F0d, cpu_F1d;
pbrookb26eefb2008-03-31 03:44:26 +000098
pbrook2e70f6e2008-06-29 01:03:05 +000099#include "gen-icount.h"
100
Filip Navara155c3ea2009-10-15 12:00:41 +0200101static const char *regnames[] =
102 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
103 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" };
104
pbrookb26eefb2008-03-31 03:44:26 +0000105/* initialize TCG globals. */
106void arm_translate_init(void)
107{
Filip Navara155c3ea2009-10-15 12:00:41 +0200108 int i;
109
pbrooka7812ae2008-11-17 14:43:54 +0000110 cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
pbrookb26eefb2008-03-31 03:44:26 +0000111
Filip Navara155c3ea2009-10-15 12:00:41 +0200112 for (i = 0; i < 16; i++) {
113 cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
114 offsetof(CPUState, regs[i]),
115 regnames[i]);
116 }
Paul Brook426f5ab2009-11-22 21:35:13 +0000117 cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0,
118 offsetof(CPUState, exclusive_addr), "exclusive_addr");
119 cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0,
120 offsetof(CPUState, exclusive_val), "exclusive_val");
121 cpu_exclusive_high = tcg_global_mem_new_i32(TCG_AREG0,
122 offsetof(CPUState, exclusive_high), "exclusive_high");
123#ifdef CONFIG_USER_ONLY
124 cpu_exclusive_test = tcg_global_mem_new_i32(TCG_AREG0,
125 offsetof(CPUState, exclusive_test), "exclusive_test");
126 cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
127 offsetof(CPUState, exclusive_info), "exclusive_info");
128#endif
Filip Navara155c3ea2009-10-15 12:00:41 +0200129
pbrooka7812ae2008-11-17 14:43:54 +0000130#define GEN_HELPER 2
Lluís7b592202011-04-13 18:38:24 +0200131#include "helper.h"
pbrookb26eefb2008-03-31 03:44:26 +0000132}
133
pbrookd9ba4832008-03-31 03:46:50 +0000134static inline TCGv load_cpu_offset(int offset)
135{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000136 TCGv tmp = tcg_temp_new_i32();
pbrookd9ba4832008-03-31 03:46:50 +0000137 tcg_gen_ld_i32(tmp, cpu_env, offset);
138 return tmp;
139}
140
141#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name))
142
143static inline void store_cpu_offset(TCGv var, int offset)
144{
145 tcg_gen_st_i32(var, cpu_env, offset);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000146 tcg_temp_free_i32(var);
pbrookd9ba4832008-03-31 03:46:50 +0000147}
148
149#define store_cpu_field(var, name) \
150 store_cpu_offset(var, offsetof(CPUState, name))
151
pbrookb26eefb2008-03-31 03:44:26 +0000152/* Set a variable to the value of a CPU register. */
153static void load_reg_var(DisasContext *s, TCGv var, int reg)
154{
155 if (reg == 15) {
156 uint32_t addr;
157 /* normaly, since we updated PC, we need only to add one insn */
158 if (s->thumb)
159 addr = (long)s->pc + 2;
160 else
161 addr = (long)s->pc + 4;
162 tcg_gen_movi_i32(var, addr);
163 } else {
Filip Navara155c3ea2009-10-15 12:00:41 +0200164 tcg_gen_mov_i32(var, cpu_R[reg]);
pbrookb26eefb2008-03-31 03:44:26 +0000165 }
166}
167
168/* Create a new temporary and set it to the value of a CPU register. */
169static inline TCGv load_reg(DisasContext *s, int reg)
170{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000171 TCGv tmp = tcg_temp_new_i32();
pbrookb26eefb2008-03-31 03:44:26 +0000172 load_reg_var(s, tmp, reg);
173 return tmp;
174}
175
176/* Set a CPU register. The source must be a temporary and will be
177 marked as dead. */
178static void store_reg(DisasContext *s, int reg, TCGv var)
179{
180 if (reg == 15) {
181 tcg_gen_andi_i32(var, var, ~1);
182 s->is_jmp = DISAS_JUMP;
183 }
Filip Navara155c3ea2009-10-15 12:00:41 +0200184 tcg_gen_mov_i32(cpu_R[reg], var);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000185 tcg_temp_free_i32(var);
pbrookb26eefb2008-03-31 03:44:26 +0000186}
187
pbrookb26eefb2008-03-31 03:44:26 +0000188/* Value extensions. */
pbrook86831432008-05-11 12:22:01 +0000189#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
190#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
pbrookb26eefb2008-03-31 03:44:26 +0000191#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
192#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)
193
pbrook1497c962008-03-31 03:45:50 +0000194#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
195#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
pbrook8f012452008-03-31 03:46:03 +0000196
pbrookb26eefb2008-03-31 03:44:26 +0000197
Juha Riihimäkib75263d2009-10-22 15:17:36 +0300198static inline void gen_set_cpsr(TCGv var, uint32_t mask)
199{
200 TCGv tmp_mask = tcg_const_i32(mask);
201 gen_helper_cpsr_write(var, tmp_mask);
202 tcg_temp_free_i32(tmp_mask);
203}
pbrookd9ba4832008-03-31 03:46:50 +0000204/* Set NZCV flags from the high 4 bits of var. */
205#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
206
207static void gen_exception(int excp)
208{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000209 TCGv tmp = tcg_temp_new_i32();
pbrookd9ba4832008-03-31 03:46:50 +0000210 tcg_gen_movi_i32(tmp, excp);
211 gen_helper_exception(tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000212 tcg_temp_free_i32(tmp);
pbrookd9ba4832008-03-31 03:46:50 +0000213}
214
pbrook36706692008-03-31 03:46:19 +0000215static void gen_smul_dual(TCGv a, TCGv b)
216{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000217 TCGv tmp1 = tcg_temp_new_i32();
218 TCGv tmp2 = tcg_temp_new_i32();
balrog22478e72008-07-19 10:12:22 +0000219 tcg_gen_ext16s_i32(tmp1, a);
220 tcg_gen_ext16s_i32(tmp2, b);
pbrook36706692008-03-31 03:46:19 +0000221 tcg_gen_mul_i32(tmp1, tmp1, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000222 tcg_temp_free_i32(tmp2);
pbrook36706692008-03-31 03:46:19 +0000223 tcg_gen_sari_i32(a, a, 16);
224 tcg_gen_sari_i32(b, b, 16);
225 tcg_gen_mul_i32(b, b, a);
226 tcg_gen_mov_i32(a, tmp1);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000227 tcg_temp_free_i32(tmp1);
pbrook36706692008-03-31 03:46:19 +0000228}
229
230/* Byteswap each halfword. */
231static void gen_rev16(TCGv var)
232{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000233 TCGv tmp = tcg_temp_new_i32();
pbrook36706692008-03-31 03:46:19 +0000234 tcg_gen_shri_i32(tmp, var, 8);
235 tcg_gen_andi_i32(tmp, tmp, 0x00ff00ff);
236 tcg_gen_shli_i32(var, var, 8);
237 tcg_gen_andi_i32(var, var, 0xff00ff00);
238 tcg_gen_or_i32(var, var, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000239 tcg_temp_free_i32(tmp);
pbrook36706692008-03-31 03:46:19 +0000240}
241
242/* Byteswap low halfword and sign extend. */
243static void gen_revsh(TCGv var)
244{
Aurelien Jarno1a855022010-12-27 19:54:49 +0100245 tcg_gen_ext16u_i32(var, var);
246 tcg_gen_bswap16_i32(var, var);
247 tcg_gen_ext16s_i32(var, var);
pbrook36706692008-03-31 03:46:19 +0000248}
249
250/* Unsigned bitfield extract. */
251static void gen_ubfx(TCGv var, int shift, uint32_t mask)
252{
253 if (shift)
254 tcg_gen_shri_i32(var, var, shift);
255 tcg_gen_andi_i32(var, var, mask);
256}
257
258/* Signed bitfield extract. */
259static void gen_sbfx(TCGv var, int shift, int width)
260{
261 uint32_t signbit;
262
263 if (shift)
264 tcg_gen_sari_i32(var, var, shift);
265 if (shift + width < 32) {
266 signbit = 1u << (width - 1);
267 tcg_gen_andi_i32(var, var, (1u << width) - 1);
268 tcg_gen_xori_i32(var, var, signbit);
269 tcg_gen_subi_i32(var, var, signbit);
270 }
271}
272
273/* Bitfield insertion. Insert val into base. Clobbers base and val. */
274static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask)
275{
pbrook36706692008-03-31 03:46:19 +0000276 tcg_gen_andi_i32(val, val, mask);
pbrook8f8e3aa2008-03-31 03:48:01 +0000277 tcg_gen_shli_i32(val, val, shift);
278 tcg_gen_andi_i32(base, base, ~(mask << shift));
pbrook36706692008-03-31 03:46:19 +0000279 tcg_gen_or_i32(dest, base, val);
280}
281
Aurelien Jarno838fa722011-01-06 19:53:56 +0100282/* Return (b << 32) + a. Mark inputs as dead */
283static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv b)
pbrook36706692008-03-31 03:46:19 +0000284{
Aurelien Jarno838fa722011-01-06 19:53:56 +0100285 TCGv_i64 tmp64 = tcg_temp_new_i64();
286
287 tcg_gen_extu_i32_i64(tmp64, b);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000288 tcg_temp_free_i32(b);
Aurelien Jarno838fa722011-01-06 19:53:56 +0100289 tcg_gen_shli_i64(tmp64, tmp64, 32);
290 tcg_gen_add_i64(a, tmp64, a);
291
292 tcg_temp_free_i64(tmp64);
293 return a;
294}
295
296/* Return (b << 32) - a. Mark inputs as dead. */
297static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv b)
298{
299 TCGv_i64 tmp64 = tcg_temp_new_i64();
300
301 tcg_gen_extu_i32_i64(tmp64, b);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000302 tcg_temp_free_i32(b);
Aurelien Jarno838fa722011-01-06 19:53:56 +0100303 tcg_gen_shli_i64(tmp64, tmp64, 32);
304 tcg_gen_sub_i64(a, tmp64, a);
305
306 tcg_temp_free_i64(tmp64);
307 return a;
pbrook36706692008-03-31 03:46:19 +0000308}
309
pbrook8f012452008-03-31 03:46:03 +0000310/* FIXME: Most targets have native widening multiplication.
311 It would be good to use that instead of a full wide multiply. */
pbrook5e3f8782008-03-31 03:47:34 +0000312/* 32x32->64 multiply. Marks inputs as dead. */
pbrooka7812ae2008-11-17 14:43:54 +0000313static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
pbrook5e3f8782008-03-31 03:47:34 +0000314{
pbrooka7812ae2008-11-17 14:43:54 +0000315 TCGv_i64 tmp1 = tcg_temp_new_i64();
316 TCGv_i64 tmp2 = tcg_temp_new_i64();
pbrook5e3f8782008-03-31 03:47:34 +0000317
318 tcg_gen_extu_i32_i64(tmp1, a);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000319 tcg_temp_free_i32(a);
pbrook5e3f8782008-03-31 03:47:34 +0000320 tcg_gen_extu_i32_i64(tmp2, b);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000321 tcg_temp_free_i32(b);
pbrook5e3f8782008-03-31 03:47:34 +0000322 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
Juha Riihimäkib75263d2009-10-22 15:17:36 +0300323 tcg_temp_free_i64(tmp2);
pbrook5e3f8782008-03-31 03:47:34 +0000324 return tmp1;
325}
326
pbrooka7812ae2008-11-17 14:43:54 +0000327static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
pbrook5e3f8782008-03-31 03:47:34 +0000328{
pbrooka7812ae2008-11-17 14:43:54 +0000329 TCGv_i64 tmp1 = tcg_temp_new_i64();
330 TCGv_i64 tmp2 = tcg_temp_new_i64();
pbrook5e3f8782008-03-31 03:47:34 +0000331
332 tcg_gen_ext_i32_i64(tmp1, a);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000333 tcg_temp_free_i32(a);
pbrook5e3f8782008-03-31 03:47:34 +0000334 tcg_gen_ext_i32_i64(tmp2, b);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000335 tcg_temp_free_i32(b);
pbrook5e3f8782008-03-31 03:47:34 +0000336 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
Juha Riihimäkib75263d2009-10-22 15:17:36 +0300337 tcg_temp_free_i64(tmp2);
pbrook5e3f8782008-03-31 03:47:34 +0000338 return tmp1;
339}
340
pbrook8f012452008-03-31 03:46:03 +0000341/* Swap low and high halfwords. */
342static void gen_swap_half(TCGv var)
343{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000344 TCGv tmp = tcg_temp_new_i32();
pbrook8f012452008-03-31 03:46:03 +0000345 tcg_gen_shri_i32(tmp, var, 16);
346 tcg_gen_shli_i32(var, var, 16);
347 tcg_gen_or_i32(var, var, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000348 tcg_temp_free_i32(tmp);
pbrook8f012452008-03-31 03:46:03 +0000349}
350
pbrookb26eefb2008-03-31 03:44:26 +0000351/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead.
352 tmp = (t0 ^ t1) & 0x8000;
353 t0 &= ~0x8000;
354 t1 &= ~0x8000;
355 t0 = (t0 + t1) ^ tmp;
356 */
357
358static void gen_add16(TCGv t0, TCGv t1)
359{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000360 TCGv tmp = tcg_temp_new_i32();
pbrookb26eefb2008-03-31 03:44:26 +0000361 tcg_gen_xor_i32(tmp, t0, t1);
362 tcg_gen_andi_i32(tmp, tmp, 0x8000);
363 tcg_gen_andi_i32(t0, t0, ~0x8000);
364 tcg_gen_andi_i32(t1, t1, ~0x8000);
365 tcg_gen_add_i32(t0, t0, t1);
366 tcg_gen_xor_i32(t0, t0, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000367 tcg_temp_free_i32(tmp);
368 tcg_temp_free_i32(t1);
pbrookb26eefb2008-03-31 03:44:26 +0000369}
370
pbrook9a119ff2008-03-31 03:45:35 +0000371#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF))
372
pbrookb26eefb2008-03-31 03:44:26 +0000373/* Set CF to the top bit of var. */
374static void gen_set_CF_bit31(TCGv var)
375{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000376 TCGv tmp = tcg_temp_new_i32();
pbrookb26eefb2008-03-31 03:44:26 +0000377 tcg_gen_shri_i32(tmp, var, 31);
balrog4cc633c2008-12-07 13:32:09 +0000378 gen_set_CF(tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000379 tcg_temp_free_i32(tmp);
pbrookb26eefb2008-03-31 03:44:26 +0000380}
381
382/* Set N and Z flags from var. */
383static inline void gen_logic_CC(TCGv var)
384{
pbrook6fbe23d2008-04-01 17:19:11 +0000385 tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF));
386 tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF));
pbrookb26eefb2008-03-31 03:44:26 +0000387}
388
389/* T0 += T1 + CF. */
Filip Navara396e4672009-10-15 12:55:34 +0200390static void gen_adc(TCGv t0, TCGv t1)
pbrookb26eefb2008-03-31 03:44:26 +0000391{
pbrookd9ba4832008-03-31 03:46:50 +0000392 TCGv tmp;
Filip Navara396e4672009-10-15 12:55:34 +0200393 tcg_gen_add_i32(t0, t0, t1);
pbrookd9ba4832008-03-31 03:46:50 +0000394 tmp = load_cpu_field(CF);
Filip Navara396e4672009-10-15 12:55:34 +0200395 tcg_gen_add_i32(t0, t0, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000396 tcg_temp_free_i32(tmp);
pbrookb26eefb2008-03-31 03:44:26 +0000397}
398
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +0300399/* dest = T0 + T1 + CF. */
400static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
401{
402 TCGv tmp;
403 tcg_gen_add_i32(dest, t0, t1);
404 tmp = load_cpu_field(CF);
405 tcg_gen_add_i32(dest, dest, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000406 tcg_temp_free_i32(tmp);
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +0300407}
408
pbrook36706692008-03-31 03:46:19 +0000409/* dest = T0 - T1 + CF - 1. */
410static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
411{
pbrookd9ba4832008-03-31 03:46:50 +0000412 TCGv tmp;
pbrook36706692008-03-31 03:46:19 +0000413 tcg_gen_sub_i32(dest, t0, t1);
pbrookd9ba4832008-03-31 03:46:50 +0000414 tmp = load_cpu_field(CF);
pbrook36706692008-03-31 03:46:19 +0000415 tcg_gen_add_i32(dest, dest, tmp);
416 tcg_gen_subi_i32(dest, dest, 1);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000417 tcg_temp_free_i32(tmp);
pbrook36706692008-03-31 03:46:19 +0000418}
419
pbrookb26eefb2008-03-31 03:44:26 +0000420/* FIXME: Implement this natively. */
pbrookad694712008-03-31 03:48:30 +0000421#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1)
422
pbrook9a119ff2008-03-31 03:45:35 +0000423static void shifter_out_im(TCGv var, int shift)
pbrookb26eefb2008-03-31 03:44:26 +0000424{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000425 TCGv tmp = tcg_temp_new_i32();
pbrook9a119ff2008-03-31 03:45:35 +0000426 if (shift == 0) {
427 tcg_gen_andi_i32(tmp, var, 1);
pbrookb26eefb2008-03-31 03:44:26 +0000428 } else {
pbrook9a119ff2008-03-31 03:45:35 +0000429 tcg_gen_shri_i32(tmp, var, shift);
balrog4cc633c2008-12-07 13:32:09 +0000430 if (shift != 31)
pbrook9a119ff2008-03-31 03:45:35 +0000431 tcg_gen_andi_i32(tmp, tmp, 1);
432 }
433 gen_set_CF(tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000434 tcg_temp_free_i32(tmp);
pbrook9a119ff2008-03-31 03:45:35 +0000435}
pbrookb26eefb2008-03-31 03:44:26 +0000436
pbrook9a119ff2008-03-31 03:45:35 +0000437/* Shift by immediate. Includes special handling for shift == 0. */
438static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags)
439{
440 switch (shiftop) {
441 case 0: /* LSL */
442 if (shift != 0) {
443 if (flags)
444 shifter_out_im(var, 32 - shift);
445 tcg_gen_shli_i32(var, var, shift);
446 }
447 break;
448 case 1: /* LSR */
449 if (shift == 0) {
450 if (flags) {
451 tcg_gen_shri_i32(var, var, 31);
452 gen_set_CF(var);
453 }
454 tcg_gen_movi_i32(var, 0);
455 } else {
456 if (flags)
457 shifter_out_im(var, shift - 1);
458 tcg_gen_shri_i32(var, var, shift);
459 }
460 break;
461 case 2: /* ASR */
462 if (shift == 0)
463 shift = 32;
464 if (flags)
465 shifter_out_im(var, shift - 1);
466 if (shift == 32)
467 shift = 31;
468 tcg_gen_sari_i32(var, var, shift);
469 break;
470 case 3: /* ROR/RRX */
471 if (shift != 0) {
472 if (flags)
473 shifter_out_im(var, shift - 1);
Aurelien Jarnof669df22009-10-15 16:45:14 +0200474 tcg_gen_rotri_i32(var, var, shift); break;
pbrook9a119ff2008-03-31 03:45:35 +0000475 } else {
pbrookd9ba4832008-03-31 03:46:50 +0000476 TCGv tmp = load_cpu_field(CF);
pbrook9a119ff2008-03-31 03:45:35 +0000477 if (flags)
478 shifter_out_im(var, 0);
479 tcg_gen_shri_i32(var, var, 1);
pbrookb26eefb2008-03-31 03:44:26 +0000480 tcg_gen_shli_i32(tmp, tmp, 31);
481 tcg_gen_or_i32(var, var, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000482 tcg_temp_free_i32(tmp);
pbrookb26eefb2008-03-31 03:44:26 +0000483 }
484 }
485};
486
pbrook8984bd22008-03-31 03:47:48 +0000487static inline void gen_arm_shift_reg(TCGv var, int shiftop,
488 TCGv shift, int flags)
489{
490 if (flags) {
491 switch (shiftop) {
492 case 0: gen_helper_shl_cc(var, var, shift); break;
493 case 1: gen_helper_shr_cc(var, var, shift); break;
494 case 2: gen_helper_sar_cc(var, var, shift); break;
495 case 3: gen_helper_ror_cc(var, var, shift); break;
496 }
497 } else {
498 switch (shiftop) {
499 case 0: gen_helper_shl(var, var, shift); break;
500 case 1: gen_helper_shr(var, var, shift); break;
501 case 2: gen_helper_sar(var, var, shift); break;
Aurelien Jarnof669df22009-10-15 16:45:14 +0200502 case 3: tcg_gen_andi_i32(shift, shift, 0x1f);
503 tcg_gen_rotr_i32(var, var, shift); break;
pbrook8984bd22008-03-31 03:47:48 +0000504 }
505 }
Peter Maydell7d1b0092011-03-06 21:39:54 +0000506 tcg_temp_free_i32(shift);
pbrook8984bd22008-03-31 03:47:48 +0000507}
508
pbrook6ddbc6e2008-03-31 03:46:33 +0000509#define PAS_OP(pfx) \
510 switch (op2) { \
511 case 0: gen_pas_helper(glue(pfx,add16)); break; \
512 case 1: gen_pas_helper(glue(pfx,addsubx)); break; \
513 case 2: gen_pas_helper(glue(pfx,subaddx)); break; \
514 case 3: gen_pas_helper(glue(pfx,sub16)); break; \
515 case 4: gen_pas_helper(glue(pfx,add8)); break; \
516 case 7: gen_pas_helper(glue(pfx,sub8)); break; \
517 }
pbrookd9ba4832008-03-31 03:46:50 +0000518static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
pbrook6ddbc6e2008-03-31 03:46:33 +0000519{
pbrooka7812ae2008-11-17 14:43:54 +0000520 TCGv_ptr tmp;
pbrook9ee6e8b2007-11-11 00:04:49 +0000521
pbrook6ddbc6e2008-03-31 03:46:33 +0000522 switch (op1) {
523#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
524 case 1:
pbrooka7812ae2008-11-17 14:43:54 +0000525 tmp = tcg_temp_new_ptr();
pbrook6ddbc6e2008-03-31 03:46:33 +0000526 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
527 PAS_OP(s)
Juha Riihimäkib75263d2009-10-22 15:17:36 +0300528 tcg_temp_free_ptr(tmp);
pbrook6ddbc6e2008-03-31 03:46:33 +0000529 break;
530 case 5:
pbrooka7812ae2008-11-17 14:43:54 +0000531 tmp = tcg_temp_new_ptr();
pbrook6ddbc6e2008-03-31 03:46:33 +0000532 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
533 PAS_OP(u)
Juha Riihimäkib75263d2009-10-22 15:17:36 +0300534 tcg_temp_free_ptr(tmp);
pbrook6ddbc6e2008-03-31 03:46:33 +0000535 break;
536#undef gen_pas_helper
537#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
538 case 2:
539 PAS_OP(q);
540 break;
541 case 3:
542 PAS_OP(sh);
543 break;
544 case 6:
545 PAS_OP(uq);
546 break;
547 case 7:
548 PAS_OP(uh);
549 break;
550#undef gen_pas_helper
551 }
552}
pbrook9ee6e8b2007-11-11 00:04:49 +0000553#undef PAS_OP
554
pbrook6ddbc6e2008-03-31 03:46:33 +0000555/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */
556#define PAS_OP(pfx) \
Chih-Min Chaoed89a2f2010-06-28 23:54:05 +0800557 switch (op1) { \
pbrook6ddbc6e2008-03-31 03:46:33 +0000558 case 0: gen_pas_helper(glue(pfx,add8)); break; \
559 case 1: gen_pas_helper(glue(pfx,add16)); break; \
560 case 2: gen_pas_helper(glue(pfx,addsubx)); break; \
561 case 4: gen_pas_helper(glue(pfx,sub8)); break; \
562 case 5: gen_pas_helper(glue(pfx,sub16)); break; \
563 case 6: gen_pas_helper(glue(pfx,subaddx)); break; \
564 }
pbrookd9ba4832008-03-31 03:46:50 +0000565static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
pbrook6ddbc6e2008-03-31 03:46:33 +0000566{
pbrooka7812ae2008-11-17 14:43:54 +0000567 TCGv_ptr tmp;
pbrook9ee6e8b2007-11-11 00:04:49 +0000568
Chih-Min Chaoed89a2f2010-06-28 23:54:05 +0800569 switch (op2) {
pbrook6ddbc6e2008-03-31 03:46:33 +0000570#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
571 case 0:
pbrooka7812ae2008-11-17 14:43:54 +0000572 tmp = tcg_temp_new_ptr();
pbrook6ddbc6e2008-03-31 03:46:33 +0000573 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
574 PAS_OP(s)
Juha Riihimäkib75263d2009-10-22 15:17:36 +0300575 tcg_temp_free_ptr(tmp);
pbrook6ddbc6e2008-03-31 03:46:33 +0000576 break;
577 case 4:
pbrooka7812ae2008-11-17 14:43:54 +0000578 tmp = tcg_temp_new_ptr();
pbrook6ddbc6e2008-03-31 03:46:33 +0000579 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
580 PAS_OP(u)
Juha Riihimäkib75263d2009-10-22 15:17:36 +0300581 tcg_temp_free_ptr(tmp);
pbrook6ddbc6e2008-03-31 03:46:33 +0000582 break;
583#undef gen_pas_helper
584#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
585 case 1:
586 PAS_OP(q);
587 break;
588 case 2:
589 PAS_OP(sh);
590 break;
591 case 5:
592 PAS_OP(uq);
593 break;
594 case 6:
595 PAS_OP(uh);
596 break;
597#undef gen_pas_helper
598 }
599}
pbrook9ee6e8b2007-11-11 00:04:49 +0000600#undef PAS_OP
601
pbrookd9ba4832008-03-31 03:46:50 +0000602static void gen_test_cc(int cc, int label)
603{
604 TCGv tmp;
605 TCGv tmp2;
pbrookd9ba4832008-03-31 03:46:50 +0000606 int inv;
607
pbrookd9ba4832008-03-31 03:46:50 +0000608 switch (cc) {
609 case 0: /* eq: Z */
pbrook6fbe23d2008-04-01 17:19:11 +0000610 tmp = load_cpu_field(ZF);
pbrookcb636692008-05-24 02:22:00 +0000611 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000612 break;
613 case 1: /* ne: !Z */
pbrook6fbe23d2008-04-01 17:19:11 +0000614 tmp = load_cpu_field(ZF);
pbrookcb636692008-05-24 02:22:00 +0000615 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000616 break;
617 case 2: /* cs: C */
618 tmp = load_cpu_field(CF);
pbrookcb636692008-05-24 02:22:00 +0000619 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000620 break;
621 case 3: /* cc: !C */
622 tmp = load_cpu_field(CF);
pbrookcb636692008-05-24 02:22:00 +0000623 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000624 break;
625 case 4: /* mi: N */
pbrook6fbe23d2008-04-01 17:19:11 +0000626 tmp = load_cpu_field(NF);
pbrookcb636692008-05-24 02:22:00 +0000627 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000628 break;
629 case 5: /* pl: !N */
pbrook6fbe23d2008-04-01 17:19:11 +0000630 tmp = load_cpu_field(NF);
pbrookcb636692008-05-24 02:22:00 +0000631 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000632 break;
633 case 6: /* vs: V */
634 tmp = load_cpu_field(VF);
pbrookcb636692008-05-24 02:22:00 +0000635 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000636 break;
637 case 7: /* vc: !V */
638 tmp = load_cpu_field(VF);
pbrookcb636692008-05-24 02:22:00 +0000639 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000640 break;
641 case 8: /* hi: C && !Z */
642 inv = gen_new_label();
643 tmp = load_cpu_field(CF);
pbrookcb636692008-05-24 02:22:00 +0000644 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000645 tcg_temp_free_i32(tmp);
pbrook6fbe23d2008-04-01 17:19:11 +0000646 tmp = load_cpu_field(ZF);
pbrookcb636692008-05-24 02:22:00 +0000647 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000648 gen_set_label(inv);
649 break;
650 case 9: /* ls: !C || Z */
651 tmp = load_cpu_field(CF);
pbrookcb636692008-05-24 02:22:00 +0000652 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000653 tcg_temp_free_i32(tmp);
pbrook6fbe23d2008-04-01 17:19:11 +0000654 tmp = load_cpu_field(ZF);
pbrookcb636692008-05-24 02:22:00 +0000655 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000656 break;
657 case 10: /* ge: N == V -> N ^ V == 0 */
658 tmp = load_cpu_field(VF);
pbrook6fbe23d2008-04-01 17:19:11 +0000659 tmp2 = load_cpu_field(NF);
pbrookd9ba4832008-03-31 03:46:50 +0000660 tcg_gen_xor_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000661 tcg_temp_free_i32(tmp2);
pbrookcb636692008-05-24 02:22:00 +0000662 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000663 break;
664 case 11: /* lt: N != V -> N ^ V != 0 */
665 tmp = load_cpu_field(VF);
pbrook6fbe23d2008-04-01 17:19:11 +0000666 tmp2 = load_cpu_field(NF);
pbrookd9ba4832008-03-31 03:46:50 +0000667 tcg_gen_xor_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000668 tcg_temp_free_i32(tmp2);
pbrookcb636692008-05-24 02:22:00 +0000669 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000670 break;
671 case 12: /* gt: !Z && N == V */
672 inv = gen_new_label();
pbrook6fbe23d2008-04-01 17:19:11 +0000673 tmp = load_cpu_field(ZF);
pbrookcb636692008-05-24 02:22:00 +0000674 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000675 tcg_temp_free_i32(tmp);
pbrookd9ba4832008-03-31 03:46:50 +0000676 tmp = load_cpu_field(VF);
pbrook6fbe23d2008-04-01 17:19:11 +0000677 tmp2 = load_cpu_field(NF);
pbrookd9ba4832008-03-31 03:46:50 +0000678 tcg_gen_xor_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000679 tcg_temp_free_i32(tmp2);
pbrookcb636692008-05-24 02:22:00 +0000680 tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000681 gen_set_label(inv);
682 break;
683 case 13: /* le: Z || N != V */
pbrook6fbe23d2008-04-01 17:19:11 +0000684 tmp = load_cpu_field(ZF);
pbrookcb636692008-05-24 02:22:00 +0000685 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000686 tcg_temp_free_i32(tmp);
pbrookd9ba4832008-03-31 03:46:50 +0000687 tmp = load_cpu_field(VF);
pbrook6fbe23d2008-04-01 17:19:11 +0000688 tmp2 = load_cpu_field(NF);
pbrookd9ba4832008-03-31 03:46:50 +0000689 tcg_gen_xor_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000690 tcg_temp_free_i32(tmp2);
pbrookcb636692008-05-24 02:22:00 +0000691 tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
pbrookd9ba4832008-03-31 03:46:50 +0000692 break;
693 default:
694 fprintf(stderr, "Bad condition code 0x%x\n", cc);
695 abort();
696 }
Peter Maydell7d1b0092011-03-06 21:39:54 +0000697 tcg_temp_free_i32(tmp);
pbrookd9ba4832008-03-31 03:46:50 +0000698}
bellard2c0262a2003-09-30 20:34:21 +0000699
blueswir1b1d8e522008-10-26 13:43:07 +0000700static const uint8_t table_logic_cc[16] = {
bellard2c0262a2003-09-30 20:34:21 +0000701 1, /* and */
702 1, /* xor */
703 0, /* sub */
704 0, /* rsb */
705 0, /* add */
706 0, /* adc */
707 0, /* sbc */
708 0, /* rsc */
709 1, /* andl */
710 1, /* xorl */
711 0, /* cmp */
712 0, /* cmn */
713 1, /* orr */
714 1, /* mov */
715 1, /* bic */
716 1, /* mvn */
717};
ths3b46e622007-09-17 08:09:54 +0000718
pbrookd9ba4832008-03-31 03:46:50 +0000719/* Set PC and Thumb state from an immediate address. */
720static inline void gen_bx_im(DisasContext *s, uint32_t addr)
bellard99c475a2005-01-31 20:45:13 +0000721{
pbrookb26eefb2008-03-31 03:44:26 +0000722 TCGv tmp;
bellard99c475a2005-01-31 20:45:13 +0000723
pbrookb26eefb2008-03-31 03:44:26 +0000724 s->is_jmp = DISAS_UPDATE;
pbrookd9ba4832008-03-31 03:46:50 +0000725 if (s->thumb != (addr & 1)) {
Peter Maydell7d1b0092011-03-06 21:39:54 +0000726 tmp = tcg_temp_new_i32();
pbrookd9ba4832008-03-31 03:46:50 +0000727 tcg_gen_movi_i32(tmp, addr & 1);
728 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb));
Peter Maydell7d1b0092011-03-06 21:39:54 +0000729 tcg_temp_free_i32(tmp);
pbrookd9ba4832008-03-31 03:46:50 +0000730 }
Filip Navara155c3ea2009-10-15 12:00:41 +0200731 tcg_gen_movi_i32(cpu_R[15], addr & ~1);
pbrookd9ba4832008-03-31 03:46:50 +0000732}
733
734/* Set PC and Thumb state from var. var is marked as dead. */
735static inline void gen_bx(DisasContext *s, TCGv var)
736{
pbrookd9ba4832008-03-31 03:46:50 +0000737 s->is_jmp = DISAS_UPDATE;
Filip Navara155c3ea2009-10-15 12:00:41 +0200738 tcg_gen_andi_i32(cpu_R[15], var, ~1);
739 tcg_gen_andi_i32(var, var, 1);
740 store_cpu_field(var, thumb);
pbrookd9ba4832008-03-31 03:46:50 +0000741}
742
Juha Riihimäki21aeb342009-05-06 09:16:12 +0300743/* Variant of store_reg which uses branch&exchange logic when storing
744 to r15 in ARM architecture v7 and above. The source must be a temporary
745 and will be marked as dead. */
746static inline void store_reg_bx(CPUState *env, DisasContext *s,
747 int reg, TCGv var)
748{
749 if (reg == 15 && ENABLE_ARCH_7) {
750 gen_bx(s, var);
751 } else {
752 store_reg(s, reg, var);
753 }
754}
755
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +0400756/* Variant of store_reg which uses branch&exchange logic when storing
757 * to r15 in ARM architecture v5T and above. This is used for storing
758 * the results of a LDR/LDM/POP into r15, and corresponds to the cases
759 * in the ARM ARM which use the LoadWritePC() pseudocode function. */
760static inline void store_reg_from_load(CPUState *env, DisasContext *s,
761 int reg, TCGv var)
762{
763 if (reg == 15 && ENABLE_ARCH_5) {
764 gen_bx(s, var);
765 } else {
766 store_reg(s, reg, var);
767 }
768}
769
pbrookb0109802008-03-31 03:47:03 +0000770static inline TCGv gen_ld8s(TCGv addr, int index)
771{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000772 TCGv tmp = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +0000773 tcg_gen_qemu_ld8s(tmp, addr, index);
774 return tmp;
775}
776static inline TCGv gen_ld8u(TCGv addr, int index)
777{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000778 TCGv tmp = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +0000779 tcg_gen_qemu_ld8u(tmp, addr, index);
780 return tmp;
781}
782static inline TCGv gen_ld16s(TCGv addr, int index)
783{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000784 TCGv tmp = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +0000785 tcg_gen_qemu_ld16s(tmp, addr, index);
786 return tmp;
787}
788static inline TCGv gen_ld16u(TCGv addr, int index)
789{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000790 TCGv tmp = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +0000791 tcg_gen_qemu_ld16u(tmp, addr, index);
792 return tmp;
793}
794static inline TCGv gen_ld32(TCGv addr, int index)
795{
Peter Maydell7d1b0092011-03-06 21:39:54 +0000796 TCGv tmp = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +0000797 tcg_gen_qemu_ld32u(tmp, addr, index);
798 return tmp;
799}
Juha Riihimäki84496232009-10-24 15:19:01 +0300800static inline TCGv_i64 gen_ld64(TCGv addr, int index)
801{
802 TCGv_i64 tmp = tcg_temp_new_i64();
803 tcg_gen_qemu_ld64(tmp, addr, index);
804 return tmp;
805}
pbrookb0109802008-03-31 03:47:03 +0000806static inline void gen_st8(TCGv val, TCGv addr, int index)
807{
808 tcg_gen_qemu_st8(val, addr, index);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000809 tcg_temp_free_i32(val);
pbrookb0109802008-03-31 03:47:03 +0000810}
811static inline void gen_st16(TCGv val, TCGv addr, int index)
812{
813 tcg_gen_qemu_st16(val, addr, index);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000814 tcg_temp_free_i32(val);
pbrookb0109802008-03-31 03:47:03 +0000815}
816static inline void gen_st32(TCGv val, TCGv addr, int index)
817{
818 tcg_gen_qemu_st32(val, addr, index);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000819 tcg_temp_free_i32(val);
pbrookb0109802008-03-31 03:47:03 +0000820}
Juha Riihimäki84496232009-10-24 15:19:01 +0300821static inline void gen_st64(TCGv_i64 val, TCGv addr, int index)
822{
823 tcg_gen_qemu_st64(val, addr, index);
824 tcg_temp_free_i64(val);
825}
bellardb5ff1b32005-11-26 10:38:39 +0000826
pbrook5e3f8782008-03-31 03:47:34 +0000827static inline void gen_set_pc_im(uint32_t val)
828{
Filip Navara155c3ea2009-10-15 12:00:41 +0200829 tcg_gen_movi_i32(cpu_R[15], val);
pbrook5e3f8782008-03-31 03:47:34 +0000830}
831
bellardb5ff1b32005-11-26 10:38:39 +0000832/* Force a TB lookup after an instruction that changes the CPU state. */
833static inline void gen_lookup_tb(DisasContext *s)
834{
Filip Navaraa6445c52009-10-15 12:45:48 +0200835 tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
bellardb5ff1b32005-11-26 10:38:39 +0000836 s->is_jmp = DISAS_UPDATE;
837}
838
pbrookb0109802008-03-31 03:47:03 +0000839static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
840 TCGv var)
bellard2c0262a2003-09-30 20:34:21 +0000841{
bellard1e8d4ee2004-12-08 23:40:14 +0000842 int val, rm, shift, shiftop;
pbrookb26eefb2008-03-31 03:44:26 +0000843 TCGv offset;
bellard2c0262a2003-09-30 20:34:21 +0000844
845 if (!(insn & (1 << 25))) {
846 /* immediate */
847 val = insn & 0xfff;
848 if (!(insn & (1 << 23)))
849 val = -val;
bellard537730b2004-02-22 13:40:57 +0000850 if (val != 0)
pbrookb0109802008-03-31 03:47:03 +0000851 tcg_gen_addi_i32(var, var, val);
bellard2c0262a2003-09-30 20:34:21 +0000852 } else {
853 /* shift/register */
854 rm = (insn) & 0xf;
855 shift = (insn >> 7) & 0x1f;
bellard1e8d4ee2004-12-08 23:40:14 +0000856 shiftop = (insn >> 5) & 3;
pbrookb26eefb2008-03-31 03:44:26 +0000857 offset = load_reg(s, rm);
pbrook9a119ff2008-03-31 03:45:35 +0000858 gen_arm_shift_im(offset, shiftop, shift, 0);
bellard2c0262a2003-09-30 20:34:21 +0000859 if (!(insn & (1 << 23)))
pbrookb0109802008-03-31 03:47:03 +0000860 tcg_gen_sub_i32(var, var, offset);
bellard2c0262a2003-09-30 20:34:21 +0000861 else
pbrookb0109802008-03-31 03:47:03 +0000862 tcg_gen_add_i32(var, var, offset);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000863 tcg_temp_free_i32(offset);
bellard2c0262a2003-09-30 20:34:21 +0000864 }
865}
866
pbrook191f9a92006-06-14 14:36:07 +0000867static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
pbrookb0109802008-03-31 03:47:03 +0000868 int extra, TCGv var)
bellard2c0262a2003-09-30 20:34:21 +0000869{
870 int val, rm;
pbrookb26eefb2008-03-31 03:44:26 +0000871 TCGv offset;
ths3b46e622007-09-17 08:09:54 +0000872
bellard2c0262a2003-09-30 20:34:21 +0000873 if (insn & (1 << 22)) {
874 /* immediate */
875 val = (insn & 0xf) | ((insn >> 4) & 0xf0);
876 if (!(insn & (1 << 23)))
877 val = -val;
pbrook18acad92007-02-14 20:17:03 +0000878 val += extra;
bellard537730b2004-02-22 13:40:57 +0000879 if (val != 0)
pbrookb0109802008-03-31 03:47:03 +0000880 tcg_gen_addi_i32(var, var, val);
bellard2c0262a2003-09-30 20:34:21 +0000881 } else {
882 /* register */
pbrook191f9a92006-06-14 14:36:07 +0000883 if (extra)
pbrookb0109802008-03-31 03:47:03 +0000884 tcg_gen_addi_i32(var, var, extra);
bellard2c0262a2003-09-30 20:34:21 +0000885 rm = (insn) & 0xf;
pbrookb26eefb2008-03-31 03:44:26 +0000886 offset = load_reg(s, rm);
bellard2c0262a2003-09-30 20:34:21 +0000887 if (!(insn & (1 << 23)))
pbrookb0109802008-03-31 03:47:03 +0000888 tcg_gen_sub_i32(var, var, offset);
bellard2c0262a2003-09-30 20:34:21 +0000889 else
pbrookb0109802008-03-31 03:47:03 +0000890 tcg_gen_add_i32(var, var, offset);
Peter Maydell7d1b0092011-03-06 21:39:54 +0000891 tcg_temp_free_i32(offset);
bellard2c0262a2003-09-30 20:34:21 +0000892 }
893}
894
Peter Maydell5aaebd12011-05-25 15:16:10 +0000895static TCGv_ptr get_fpstatus_ptr(int neon)
896{
897 TCGv_ptr statusptr = tcg_temp_new_ptr();
898 int offset;
899 if (neon) {
900 offset = offsetof(CPUState, vfp.standard_fp_status);
901 } else {
902 offset = offsetof(CPUState, vfp.fp_status);
903 }
904 tcg_gen_addi_ptr(statusptr, cpu_env, offset);
905 return statusptr;
906}
907
pbrook4373f3c2008-03-31 03:47:19 +0000908#define VFP_OP2(name) \
909static inline void gen_vfp_##name(int dp) \
910{ \
Peter Maydellae1857e2011-05-25 14:51:48 +0000911 TCGv_ptr fpst = get_fpstatus_ptr(0); \
912 if (dp) { \
913 gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, fpst); \
914 } else { \
915 gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, fpst); \
916 } \
917 tcg_temp_free_ptr(fpst); \
bellardb7bcbe92005-02-22 19:27:29 +0000918}
919
pbrook4373f3c2008-03-31 03:47:19 +0000920VFP_OP2(add)
921VFP_OP2(sub)
922VFP_OP2(mul)
923VFP_OP2(div)
bellardb7bcbe92005-02-22 19:27:29 +0000924
pbrook4373f3c2008-03-31 03:47:19 +0000925#undef VFP_OP2
bellardb7bcbe92005-02-22 19:27:29 +0000926
Peter Maydell605a6ae2011-05-05 19:35:35 +0100927static inline void gen_vfp_F1_mul(int dp)
928{
929 /* Like gen_vfp_mul() but put result in F1 */
Peter Maydellae1857e2011-05-25 14:51:48 +0000930 TCGv_ptr fpst = get_fpstatus_ptr(0);
Peter Maydell605a6ae2011-05-05 19:35:35 +0100931 if (dp) {
Peter Maydellae1857e2011-05-25 14:51:48 +0000932 gen_helper_vfp_muld(cpu_F1d, cpu_F0d, cpu_F1d, fpst);
Peter Maydell605a6ae2011-05-05 19:35:35 +0100933 } else {
Peter Maydellae1857e2011-05-25 14:51:48 +0000934 gen_helper_vfp_muls(cpu_F1s, cpu_F0s, cpu_F1s, fpst);
Peter Maydell605a6ae2011-05-05 19:35:35 +0100935 }
Peter Maydellae1857e2011-05-25 14:51:48 +0000936 tcg_temp_free_ptr(fpst);
Peter Maydell605a6ae2011-05-05 19:35:35 +0100937}
938
939static inline void gen_vfp_F1_neg(int dp)
940{
941 /* Like gen_vfp_neg() but put result in F1 */
942 if (dp) {
943 gen_helper_vfp_negd(cpu_F1d, cpu_F0d);
944 } else {
945 gen_helper_vfp_negs(cpu_F1s, cpu_F0s);
946 }
947}
948
pbrook4373f3c2008-03-31 03:47:19 +0000949static inline void gen_vfp_abs(int dp)
pbrook9ee6e8b2007-11-11 00:04:49 +0000950{
951 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +0000952 gen_helper_vfp_absd(cpu_F0d, cpu_F0d);
pbrook9ee6e8b2007-11-11 00:04:49 +0000953 else
pbrook4373f3c2008-03-31 03:47:19 +0000954 gen_helper_vfp_abss(cpu_F0s, cpu_F0s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000955}
956
pbrook4373f3c2008-03-31 03:47:19 +0000957static inline void gen_vfp_neg(int dp)
958{
959 if (dp)
960 gen_helper_vfp_negd(cpu_F0d, cpu_F0d);
961 else
962 gen_helper_vfp_negs(cpu_F0s, cpu_F0s);
963}
964
965static inline void gen_vfp_sqrt(int dp)
966{
967 if (dp)
968 gen_helper_vfp_sqrtd(cpu_F0d, cpu_F0d, cpu_env);
969 else
970 gen_helper_vfp_sqrts(cpu_F0s, cpu_F0s, cpu_env);
971}
972
973static inline void gen_vfp_cmp(int dp)
974{
975 if (dp)
976 gen_helper_vfp_cmpd(cpu_F0d, cpu_F1d, cpu_env);
977 else
978 gen_helper_vfp_cmps(cpu_F0s, cpu_F1s, cpu_env);
979}
980
981static inline void gen_vfp_cmpe(int dp)
982{
983 if (dp)
984 gen_helper_vfp_cmped(cpu_F0d, cpu_F1d, cpu_env);
985 else
986 gen_helper_vfp_cmpes(cpu_F0s, cpu_F1s, cpu_env);
987}
988
989static inline void gen_vfp_F1_ld0(int dp)
990{
991 if (dp)
balrog5b340b52008-04-14 02:19:57 +0000992 tcg_gen_movi_i64(cpu_F1d, 0);
pbrook4373f3c2008-03-31 03:47:19 +0000993 else
balrog5b340b52008-04-14 02:19:57 +0000994 tcg_gen_movi_i32(cpu_F1s, 0);
pbrook4373f3c2008-03-31 03:47:19 +0000995}
996
Peter Maydell5500b062011-05-19 14:46:19 +0100997#define VFP_GEN_ITOF(name) \
998static inline void gen_vfp_##name(int dp, int neon) \
999{ \
Peter Maydell5aaebd12011-05-25 15:16:10 +00001000 TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
Peter Maydell5500b062011-05-19 14:46:19 +01001001 if (dp) { \
1002 gen_helper_vfp_##name##d(cpu_F0d, cpu_F0s, statusptr); \
1003 } else { \
1004 gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
1005 } \
Peter Maydellb7fa9212011-05-26 12:03:36 +01001006 tcg_temp_free_ptr(statusptr); \
pbrook4373f3c2008-03-31 03:47:19 +00001007}
1008
Peter Maydell5500b062011-05-19 14:46:19 +01001009VFP_GEN_ITOF(uito)
1010VFP_GEN_ITOF(sito)
1011#undef VFP_GEN_ITOF
1012
1013#define VFP_GEN_FTOI(name) \
1014static inline void gen_vfp_##name(int dp, int neon) \
1015{ \
Peter Maydell5aaebd12011-05-25 15:16:10 +00001016 TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
Peter Maydell5500b062011-05-19 14:46:19 +01001017 if (dp) { \
1018 gen_helper_vfp_##name##d(cpu_F0s, cpu_F0d, statusptr); \
1019 } else { \
1020 gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
1021 } \
Peter Maydellb7fa9212011-05-26 12:03:36 +01001022 tcg_temp_free_ptr(statusptr); \
pbrook4373f3c2008-03-31 03:47:19 +00001023}
1024
Peter Maydell5500b062011-05-19 14:46:19 +01001025VFP_GEN_FTOI(toui)
1026VFP_GEN_FTOI(touiz)
1027VFP_GEN_FTOI(tosi)
1028VFP_GEN_FTOI(tosiz)
1029#undef VFP_GEN_FTOI
pbrook4373f3c2008-03-31 03:47:19 +00001030
1031#define VFP_GEN_FIX(name) \
Peter Maydell5500b062011-05-19 14:46:19 +01001032static inline void gen_vfp_##name(int dp, int shift, int neon) \
pbrook4373f3c2008-03-31 03:47:19 +00001033{ \
Juha Riihimäkib75263d2009-10-22 15:17:36 +03001034 TCGv tmp_shift = tcg_const_i32(shift); \
Peter Maydell5aaebd12011-05-25 15:16:10 +00001035 TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
Peter Maydell5500b062011-05-19 14:46:19 +01001036 if (dp) { \
1037 gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tmp_shift, statusptr); \
1038 } else { \
1039 gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tmp_shift, statusptr); \
1040 } \
Juha Riihimäkib75263d2009-10-22 15:17:36 +03001041 tcg_temp_free_i32(tmp_shift); \
Peter Maydellb7fa9212011-05-26 12:03:36 +01001042 tcg_temp_free_ptr(statusptr); \
pbrook4373f3c2008-03-31 03:47:19 +00001043}
1044VFP_GEN_FIX(tosh)
1045VFP_GEN_FIX(tosl)
1046VFP_GEN_FIX(touh)
1047VFP_GEN_FIX(toul)
1048VFP_GEN_FIX(shto)
1049VFP_GEN_FIX(slto)
1050VFP_GEN_FIX(uhto)
1051VFP_GEN_FIX(ulto)
1052#undef VFP_GEN_FIX
1053
Filip Navara312eea92009-10-15 14:48:19 +02001054static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv addr)
bellardb5ff1b32005-11-26 10:38:39 +00001055{
1056 if (dp)
Filip Navara312eea92009-10-15 14:48:19 +02001057 tcg_gen_qemu_ld64(cpu_F0d, addr, IS_USER(s));
bellardb5ff1b32005-11-26 10:38:39 +00001058 else
Filip Navara312eea92009-10-15 14:48:19 +02001059 tcg_gen_qemu_ld32u(cpu_F0s, addr, IS_USER(s));
bellardb5ff1b32005-11-26 10:38:39 +00001060}
1061
Filip Navara312eea92009-10-15 14:48:19 +02001062static inline void gen_vfp_st(DisasContext *s, int dp, TCGv addr)
bellardb5ff1b32005-11-26 10:38:39 +00001063{
1064 if (dp)
Filip Navara312eea92009-10-15 14:48:19 +02001065 tcg_gen_qemu_st64(cpu_F0d, addr, IS_USER(s));
bellardb5ff1b32005-11-26 10:38:39 +00001066 else
Filip Navara312eea92009-10-15 14:48:19 +02001067 tcg_gen_qemu_st32(cpu_F0s, addr, IS_USER(s));
bellardb5ff1b32005-11-26 10:38:39 +00001068}
1069
bellard8e960052005-04-07 19:42:46 +00001070static inline long
1071vfp_reg_offset (int dp, int reg)
1072{
1073 if (dp)
1074 return offsetof(CPUARMState, vfp.regs[reg]);
1075 else if (reg & 1) {
1076 return offsetof(CPUARMState, vfp.regs[reg >> 1])
1077 + offsetof(CPU_DoubleU, l.upper);
1078 } else {
1079 return offsetof(CPUARMState, vfp.regs[reg >> 1])
1080 + offsetof(CPU_DoubleU, l.lower);
1081 }
1082}
pbrook9ee6e8b2007-11-11 00:04:49 +00001083
1084/* Return the offset of a 32-bit piece of a NEON register.
1085 zero is the least significant end of the register. */
1086static inline long
1087neon_reg_offset (int reg, int n)
1088{
1089 int sreg;
1090 sreg = reg * 2 + n;
1091 return vfp_reg_offset(0, sreg);
1092}
1093
pbrook8f8e3aa2008-03-31 03:48:01 +00001094static TCGv neon_load_reg(int reg, int pass)
1095{
Peter Maydell7d1b0092011-03-06 21:39:54 +00001096 TCGv tmp = tcg_temp_new_i32();
pbrook8f8e3aa2008-03-31 03:48:01 +00001097 tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass));
1098 return tmp;
1099}
1100
1101static void neon_store_reg(int reg, int pass, TCGv var)
1102{
1103 tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass));
Peter Maydell7d1b0092011-03-06 21:39:54 +00001104 tcg_temp_free_i32(var);
pbrook8f8e3aa2008-03-31 03:48:01 +00001105}
1106
pbrooka7812ae2008-11-17 14:43:54 +00001107static inline void neon_load_reg64(TCGv_i64 var, int reg)
pbrookad694712008-03-31 03:48:30 +00001108{
1109 tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
1110}
1111
pbrooka7812ae2008-11-17 14:43:54 +00001112static inline void neon_store_reg64(TCGv_i64 var, int reg)
pbrookad694712008-03-31 03:48:30 +00001113{
1114 tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
1115}
1116
pbrook4373f3c2008-03-31 03:47:19 +00001117#define tcg_gen_ld_f32 tcg_gen_ld_i32
1118#define tcg_gen_ld_f64 tcg_gen_ld_i64
1119#define tcg_gen_st_f32 tcg_gen_st_i32
1120#define tcg_gen_st_f64 tcg_gen_st_i64
1121
bellardb7bcbe92005-02-22 19:27:29 +00001122static inline void gen_mov_F0_vreg(int dp, int reg)
1123{
1124 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00001125 tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001126 else
pbrook4373f3c2008-03-31 03:47:19 +00001127 tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001128}
1129
1130static inline void gen_mov_F1_vreg(int dp, int reg)
1131{
1132 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00001133 tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001134 else
pbrook4373f3c2008-03-31 03:47:19 +00001135 tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001136}
1137
1138static inline void gen_mov_vreg_F0(int dp, int reg)
1139{
1140 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00001141 tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001142 else
pbrook4373f3c2008-03-31 03:47:19 +00001143 tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001144}
1145
balrog18c9b562007-04-30 02:02:17 +00001146#define ARM_CP_RW_BIT (1 << 20)
1147
pbrooka7812ae2008-11-17 14:43:54 +00001148static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
pbrooke6771372008-03-31 03:49:05 +00001149{
1150 tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
1151}
1152
pbrooka7812ae2008-11-17 14:43:54 +00001153static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
pbrooke6771372008-03-31 03:49:05 +00001154{
1155 tcg_gen_st_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
1156}
1157
Filip Navarada6b5332009-10-15 14:39:02 +02001158static inline TCGv iwmmxt_load_creg(int reg)
pbrooke6771372008-03-31 03:49:05 +00001159{
Peter Maydell7d1b0092011-03-06 21:39:54 +00001160 TCGv var = tcg_temp_new_i32();
Filip Navarada6b5332009-10-15 14:39:02 +02001161 tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
1162 return var;
pbrooke6771372008-03-31 03:49:05 +00001163}
1164
Filip Navarada6b5332009-10-15 14:39:02 +02001165static inline void iwmmxt_store_creg(int reg, TCGv var)
pbrooke6771372008-03-31 03:49:05 +00001166{
Filip Navarada6b5332009-10-15 14:39:02 +02001167 tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
Peter Maydell7d1b0092011-03-06 21:39:54 +00001168 tcg_temp_free_i32(var);
pbrooke6771372008-03-31 03:49:05 +00001169}
1170
1171static inline void gen_op_iwmmxt_movq_wRn_M0(int rn)
1172{
1173 iwmmxt_store_reg(cpu_M0, rn);
1174}
1175
1176static inline void gen_op_iwmmxt_movq_M0_wRn(int rn)
1177{
1178 iwmmxt_load_reg(cpu_M0, rn);
1179}
1180
1181static inline void gen_op_iwmmxt_orq_M0_wRn(int rn)
1182{
1183 iwmmxt_load_reg(cpu_V1, rn);
1184 tcg_gen_or_i64(cpu_M0, cpu_M0, cpu_V1);
1185}
1186
1187static inline void gen_op_iwmmxt_andq_M0_wRn(int rn)
1188{
1189 iwmmxt_load_reg(cpu_V1, rn);
1190 tcg_gen_and_i64(cpu_M0, cpu_M0, cpu_V1);
1191}
1192
1193static inline void gen_op_iwmmxt_xorq_M0_wRn(int rn)
1194{
1195 iwmmxt_load_reg(cpu_V1, rn);
1196 tcg_gen_xor_i64(cpu_M0, cpu_M0, cpu_V1);
1197}
1198
1199#define IWMMXT_OP(name) \
1200static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
1201{ \
1202 iwmmxt_load_reg(cpu_V1, rn); \
1203 gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \
1204}
1205
Peter Maydell477955b2011-05-25 13:22:31 +00001206#define IWMMXT_OP_ENV(name) \
1207static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
1208{ \
1209 iwmmxt_load_reg(cpu_V1, rn); \
1210 gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \
1211}
pbrooke6771372008-03-31 03:49:05 +00001212
Peter Maydell477955b2011-05-25 13:22:31 +00001213#define IWMMXT_OP_ENV_SIZE(name) \
1214IWMMXT_OP_ENV(name##b) \
1215IWMMXT_OP_ENV(name##w) \
1216IWMMXT_OP_ENV(name##l)
1217
1218#define IWMMXT_OP_ENV1(name) \
pbrooke6771372008-03-31 03:49:05 +00001219static inline void gen_op_iwmmxt_##name##_M0(void) \
1220{ \
Peter Maydell477955b2011-05-25 13:22:31 +00001221 gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \
pbrooke6771372008-03-31 03:49:05 +00001222}
1223
1224IWMMXT_OP(maddsq)
1225IWMMXT_OP(madduq)
1226IWMMXT_OP(sadb)
1227IWMMXT_OP(sadw)
1228IWMMXT_OP(mulslw)
1229IWMMXT_OP(mulshw)
1230IWMMXT_OP(mululw)
1231IWMMXT_OP(muluhw)
1232IWMMXT_OP(macsw)
1233IWMMXT_OP(macuw)
1234
Peter Maydell477955b2011-05-25 13:22:31 +00001235IWMMXT_OP_ENV_SIZE(unpackl)
1236IWMMXT_OP_ENV_SIZE(unpackh)
pbrooke6771372008-03-31 03:49:05 +00001237
Peter Maydell477955b2011-05-25 13:22:31 +00001238IWMMXT_OP_ENV1(unpacklub)
1239IWMMXT_OP_ENV1(unpackluw)
1240IWMMXT_OP_ENV1(unpacklul)
1241IWMMXT_OP_ENV1(unpackhub)
1242IWMMXT_OP_ENV1(unpackhuw)
1243IWMMXT_OP_ENV1(unpackhul)
1244IWMMXT_OP_ENV1(unpacklsb)
1245IWMMXT_OP_ENV1(unpacklsw)
1246IWMMXT_OP_ENV1(unpacklsl)
1247IWMMXT_OP_ENV1(unpackhsb)
1248IWMMXT_OP_ENV1(unpackhsw)
1249IWMMXT_OP_ENV1(unpackhsl)
pbrooke6771372008-03-31 03:49:05 +00001250
Peter Maydell477955b2011-05-25 13:22:31 +00001251IWMMXT_OP_ENV_SIZE(cmpeq)
1252IWMMXT_OP_ENV_SIZE(cmpgtu)
1253IWMMXT_OP_ENV_SIZE(cmpgts)
pbrooke6771372008-03-31 03:49:05 +00001254
Peter Maydell477955b2011-05-25 13:22:31 +00001255IWMMXT_OP_ENV_SIZE(mins)
1256IWMMXT_OP_ENV_SIZE(minu)
1257IWMMXT_OP_ENV_SIZE(maxs)
1258IWMMXT_OP_ENV_SIZE(maxu)
pbrooke6771372008-03-31 03:49:05 +00001259
Peter Maydell477955b2011-05-25 13:22:31 +00001260IWMMXT_OP_ENV_SIZE(subn)
1261IWMMXT_OP_ENV_SIZE(addn)
1262IWMMXT_OP_ENV_SIZE(subu)
1263IWMMXT_OP_ENV_SIZE(addu)
1264IWMMXT_OP_ENV_SIZE(subs)
1265IWMMXT_OP_ENV_SIZE(adds)
pbrooke6771372008-03-31 03:49:05 +00001266
Peter Maydell477955b2011-05-25 13:22:31 +00001267IWMMXT_OP_ENV(avgb0)
1268IWMMXT_OP_ENV(avgb1)
1269IWMMXT_OP_ENV(avgw0)
1270IWMMXT_OP_ENV(avgw1)
pbrooke6771372008-03-31 03:49:05 +00001271
1272IWMMXT_OP(msadb)
1273
Peter Maydell477955b2011-05-25 13:22:31 +00001274IWMMXT_OP_ENV(packuw)
1275IWMMXT_OP_ENV(packul)
1276IWMMXT_OP_ENV(packuq)
1277IWMMXT_OP_ENV(packsw)
1278IWMMXT_OP_ENV(packsl)
1279IWMMXT_OP_ENV(packsq)
pbrooke6771372008-03-31 03:49:05 +00001280
pbrooke6771372008-03-31 03:49:05 +00001281static void gen_op_iwmmxt_set_mup(void)
1282{
1283 TCGv tmp;
1284 tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
1285 tcg_gen_ori_i32(tmp, tmp, 2);
1286 store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
1287}
1288
1289static void gen_op_iwmmxt_set_cup(void)
1290{
1291 TCGv tmp;
1292 tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
1293 tcg_gen_ori_i32(tmp, tmp, 1);
1294 store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
1295}
1296
1297static void gen_op_iwmmxt_setpsr_nz(void)
1298{
Peter Maydell7d1b0092011-03-06 21:39:54 +00001299 TCGv tmp = tcg_temp_new_i32();
pbrooke6771372008-03-31 03:49:05 +00001300 gen_helper_iwmmxt_setpsr_nz(tmp, cpu_M0);
1301 store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCASF]);
1302}
1303
1304static inline void gen_op_iwmmxt_addl_M0_wRn(int rn)
1305{
1306 iwmmxt_load_reg(cpu_V1, rn);
pbrook86831432008-05-11 12:22:01 +00001307 tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
pbrooke6771372008-03-31 03:49:05 +00001308 tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1309}
1310
Filip Navarada6b5332009-10-15 14:39:02 +02001311static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn, TCGv dest)
balrog18c9b562007-04-30 02:02:17 +00001312{
1313 int rd;
1314 uint32_t offset;
Filip Navarada6b5332009-10-15 14:39:02 +02001315 TCGv tmp;
balrog18c9b562007-04-30 02:02:17 +00001316
1317 rd = (insn >> 16) & 0xf;
Filip Navarada6b5332009-10-15 14:39:02 +02001318 tmp = load_reg(s, rd);
balrog18c9b562007-04-30 02:02:17 +00001319
1320 offset = (insn & 0xff) << ((insn >> 7) & 2);
1321 if (insn & (1 << 24)) {
1322 /* Pre indexed */
1323 if (insn & (1 << 23))
Filip Navarada6b5332009-10-15 14:39:02 +02001324 tcg_gen_addi_i32(tmp, tmp, offset);
balrog18c9b562007-04-30 02:02:17 +00001325 else
Filip Navarada6b5332009-10-15 14:39:02 +02001326 tcg_gen_addi_i32(tmp, tmp, -offset);
1327 tcg_gen_mov_i32(dest, tmp);
balrog18c9b562007-04-30 02:02:17 +00001328 if (insn & (1 << 21))
Filip Navarada6b5332009-10-15 14:39:02 +02001329 store_reg(s, rd, tmp);
1330 else
Peter Maydell7d1b0092011-03-06 21:39:54 +00001331 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00001332 } else if (insn & (1 << 21)) {
1333 /* Post indexed */
Filip Navarada6b5332009-10-15 14:39:02 +02001334 tcg_gen_mov_i32(dest, tmp);
balrog18c9b562007-04-30 02:02:17 +00001335 if (insn & (1 << 23))
Filip Navarada6b5332009-10-15 14:39:02 +02001336 tcg_gen_addi_i32(tmp, tmp, offset);
balrog18c9b562007-04-30 02:02:17 +00001337 else
Filip Navarada6b5332009-10-15 14:39:02 +02001338 tcg_gen_addi_i32(tmp, tmp, -offset);
1339 store_reg(s, rd, tmp);
balrog18c9b562007-04-30 02:02:17 +00001340 } else if (!(insn & (1 << 23)))
1341 return 1;
1342 return 0;
1343}
1344
Filip Navarada6b5332009-10-15 14:39:02 +02001345static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv dest)
balrog18c9b562007-04-30 02:02:17 +00001346{
1347 int rd = (insn >> 0) & 0xf;
Filip Navarada6b5332009-10-15 14:39:02 +02001348 TCGv tmp;
balrog18c9b562007-04-30 02:02:17 +00001349
Filip Navarada6b5332009-10-15 14:39:02 +02001350 if (insn & (1 << 8)) {
1351 if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) {
balrog18c9b562007-04-30 02:02:17 +00001352 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02001353 } else {
1354 tmp = iwmmxt_load_creg(rd);
1355 }
1356 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00001357 tmp = tcg_temp_new_i32();
Filip Navarada6b5332009-10-15 14:39:02 +02001358 iwmmxt_load_reg(cpu_V0, rd);
1359 tcg_gen_trunc_i64_i32(tmp, cpu_V0);
1360 }
1361 tcg_gen_andi_i32(tmp, tmp, mask);
1362 tcg_gen_mov_i32(dest, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001363 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00001364 return 0;
1365}
1366
Stefan Weila1c72732011-04-28 17:20:38 +02001367/* Disassemble an iwMMXt instruction. Returns nonzero if an error occurred
balrog18c9b562007-04-30 02:02:17 +00001368 (ie. an undefined instruction). */
1369static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
1370{
1371 int rd, wrd;
1372 int rdhi, rdlo, rd0, rd1, i;
Filip Navarada6b5332009-10-15 14:39:02 +02001373 TCGv addr;
1374 TCGv tmp, tmp2, tmp3;
balrog18c9b562007-04-30 02:02:17 +00001375
1376 if ((insn & 0x0e000e00) == 0x0c000000) {
1377 if ((insn & 0x0fe00ff0) == 0x0c400000) {
1378 wrd = insn & 0xf;
1379 rdlo = (insn >> 12) & 0xf;
1380 rdhi = (insn >> 16) & 0xf;
1381 if (insn & ARM_CP_RW_BIT) { /* TMRRC */
Filip Navarada6b5332009-10-15 14:39:02 +02001382 iwmmxt_load_reg(cpu_V0, wrd);
1383 tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0);
1384 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
1385 tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0);
balrog18c9b562007-04-30 02:02:17 +00001386 } else { /* TMCRR */
Filip Navarada6b5332009-10-15 14:39:02 +02001387 tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
1388 iwmmxt_store_reg(cpu_V0, wrd);
balrog18c9b562007-04-30 02:02:17 +00001389 gen_op_iwmmxt_set_mup();
1390 }
1391 return 0;
1392 }
1393
1394 wrd = (insn >> 12) & 0xf;
Peter Maydell7d1b0092011-03-06 21:39:54 +00001395 addr = tcg_temp_new_i32();
Filip Navarada6b5332009-10-15 14:39:02 +02001396 if (gen_iwmmxt_address(s, insn, addr)) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00001397 tcg_temp_free_i32(addr);
balrog18c9b562007-04-30 02:02:17 +00001398 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02001399 }
balrog18c9b562007-04-30 02:02:17 +00001400 if (insn & ARM_CP_RW_BIT) {
1401 if ((insn >> 28) == 0xf) { /* WLDRW wCx */
Peter Maydell7d1b0092011-03-06 21:39:54 +00001402 tmp = tcg_temp_new_i32();
Filip Navarada6b5332009-10-15 14:39:02 +02001403 tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
1404 iwmmxt_store_creg(wrd, tmp);
balrog18c9b562007-04-30 02:02:17 +00001405 } else {
pbrooke6771372008-03-31 03:49:05 +00001406 i = 1;
1407 if (insn & (1 << 8)) {
1408 if (insn & (1 << 22)) { /* WLDRD */
Filip Navarada6b5332009-10-15 14:39:02 +02001409 tcg_gen_qemu_ld64(cpu_M0, addr, IS_USER(s));
pbrooke6771372008-03-31 03:49:05 +00001410 i = 0;
1411 } else { /* WLDRW wRd */
Filip Navarada6b5332009-10-15 14:39:02 +02001412 tmp = gen_ld32(addr, IS_USER(s));
pbrooke6771372008-03-31 03:49:05 +00001413 }
1414 } else {
1415 if (insn & (1 << 22)) { /* WLDRH */
Filip Navarada6b5332009-10-15 14:39:02 +02001416 tmp = gen_ld16u(addr, IS_USER(s));
pbrooke6771372008-03-31 03:49:05 +00001417 } else { /* WLDRB */
Filip Navarada6b5332009-10-15 14:39:02 +02001418 tmp = gen_ld8u(addr, IS_USER(s));
pbrooke6771372008-03-31 03:49:05 +00001419 }
1420 }
1421 if (i) {
1422 tcg_gen_extu_i32_i64(cpu_M0, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001423 tcg_temp_free_i32(tmp);
pbrooke6771372008-03-31 03:49:05 +00001424 }
balrog18c9b562007-04-30 02:02:17 +00001425 gen_op_iwmmxt_movq_wRn_M0(wrd);
1426 }
1427 } else {
1428 if ((insn >> 28) == 0xf) { /* WSTRW wCx */
Filip Navarada6b5332009-10-15 14:39:02 +02001429 tmp = iwmmxt_load_creg(wrd);
1430 gen_st32(tmp, addr, IS_USER(s));
balrog18c9b562007-04-30 02:02:17 +00001431 } else {
1432 gen_op_iwmmxt_movq_M0_wRn(wrd);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001433 tmp = tcg_temp_new_i32();
pbrooke6771372008-03-31 03:49:05 +00001434 if (insn & (1 << 8)) {
1435 if (insn & (1 << 22)) { /* WSTRD */
Peter Maydell7d1b0092011-03-06 21:39:54 +00001436 tcg_temp_free_i32(tmp);
Filip Navarada6b5332009-10-15 14:39:02 +02001437 tcg_gen_qemu_st64(cpu_M0, addr, IS_USER(s));
pbrooke6771372008-03-31 03:49:05 +00001438 } else { /* WSTRW wRd */
1439 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
Filip Navarada6b5332009-10-15 14:39:02 +02001440 gen_st32(tmp, addr, IS_USER(s));
pbrooke6771372008-03-31 03:49:05 +00001441 }
1442 } else {
1443 if (insn & (1 << 22)) { /* WSTRH */
1444 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
Filip Navarada6b5332009-10-15 14:39:02 +02001445 gen_st16(tmp, addr, IS_USER(s));
pbrooke6771372008-03-31 03:49:05 +00001446 } else { /* WSTRB */
1447 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
Filip Navarada6b5332009-10-15 14:39:02 +02001448 gen_st8(tmp, addr, IS_USER(s));
pbrooke6771372008-03-31 03:49:05 +00001449 }
1450 }
balrog18c9b562007-04-30 02:02:17 +00001451 }
1452 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00001453 tcg_temp_free_i32(addr);
balrog18c9b562007-04-30 02:02:17 +00001454 return 0;
1455 }
1456
1457 if ((insn & 0x0f000000) != 0x0e000000)
1458 return 1;
1459
1460 switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
1461 case 0x000: /* WOR */
1462 wrd = (insn >> 12) & 0xf;
1463 rd0 = (insn >> 0) & 0xf;
1464 rd1 = (insn >> 16) & 0xf;
1465 gen_op_iwmmxt_movq_M0_wRn(rd0);
1466 gen_op_iwmmxt_orq_M0_wRn(rd1);
1467 gen_op_iwmmxt_setpsr_nz();
1468 gen_op_iwmmxt_movq_wRn_M0(wrd);
1469 gen_op_iwmmxt_set_mup();
1470 gen_op_iwmmxt_set_cup();
1471 break;
1472 case 0x011: /* TMCR */
1473 if (insn & 0xf)
1474 return 1;
1475 rd = (insn >> 12) & 0xf;
1476 wrd = (insn >> 16) & 0xf;
1477 switch (wrd) {
1478 case ARM_IWMMXT_wCID:
1479 case ARM_IWMMXT_wCASF:
1480 break;
1481 case ARM_IWMMXT_wCon:
1482 gen_op_iwmmxt_set_cup();
1483 /* Fall through. */
1484 case ARM_IWMMXT_wCSSF:
Filip Navarada6b5332009-10-15 14:39:02 +02001485 tmp = iwmmxt_load_creg(wrd);
1486 tmp2 = load_reg(s, rd);
Aurelien Jarnof669df22009-10-15 16:45:14 +02001487 tcg_gen_andc_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001488 tcg_temp_free_i32(tmp2);
Filip Navarada6b5332009-10-15 14:39:02 +02001489 iwmmxt_store_creg(wrd, tmp);
balrog18c9b562007-04-30 02:02:17 +00001490 break;
1491 case ARM_IWMMXT_wCGR0:
1492 case ARM_IWMMXT_wCGR1:
1493 case ARM_IWMMXT_wCGR2:
1494 case ARM_IWMMXT_wCGR3:
1495 gen_op_iwmmxt_set_cup();
Filip Navarada6b5332009-10-15 14:39:02 +02001496 tmp = load_reg(s, rd);
1497 iwmmxt_store_creg(wrd, tmp);
balrog18c9b562007-04-30 02:02:17 +00001498 break;
1499 default:
1500 return 1;
1501 }
1502 break;
1503 case 0x100: /* WXOR */
1504 wrd = (insn >> 12) & 0xf;
1505 rd0 = (insn >> 0) & 0xf;
1506 rd1 = (insn >> 16) & 0xf;
1507 gen_op_iwmmxt_movq_M0_wRn(rd0);
1508 gen_op_iwmmxt_xorq_M0_wRn(rd1);
1509 gen_op_iwmmxt_setpsr_nz();
1510 gen_op_iwmmxt_movq_wRn_M0(wrd);
1511 gen_op_iwmmxt_set_mup();
1512 gen_op_iwmmxt_set_cup();
1513 break;
1514 case 0x111: /* TMRC */
1515 if (insn & 0xf)
1516 return 1;
1517 rd = (insn >> 12) & 0xf;
1518 wrd = (insn >> 16) & 0xf;
Filip Navarada6b5332009-10-15 14:39:02 +02001519 tmp = iwmmxt_load_creg(wrd);
1520 store_reg(s, rd, tmp);
balrog18c9b562007-04-30 02:02:17 +00001521 break;
1522 case 0x300: /* WANDN */
1523 wrd = (insn >> 12) & 0xf;
1524 rd0 = (insn >> 0) & 0xf;
1525 rd1 = (insn >> 16) & 0xf;
1526 gen_op_iwmmxt_movq_M0_wRn(rd0);
pbrooke6771372008-03-31 03:49:05 +00001527 tcg_gen_neg_i64(cpu_M0, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001528 gen_op_iwmmxt_andq_M0_wRn(rd1);
1529 gen_op_iwmmxt_setpsr_nz();
1530 gen_op_iwmmxt_movq_wRn_M0(wrd);
1531 gen_op_iwmmxt_set_mup();
1532 gen_op_iwmmxt_set_cup();
1533 break;
1534 case 0x200: /* WAND */
1535 wrd = (insn >> 12) & 0xf;
1536 rd0 = (insn >> 0) & 0xf;
1537 rd1 = (insn >> 16) & 0xf;
1538 gen_op_iwmmxt_movq_M0_wRn(rd0);
1539 gen_op_iwmmxt_andq_M0_wRn(rd1);
1540 gen_op_iwmmxt_setpsr_nz();
1541 gen_op_iwmmxt_movq_wRn_M0(wrd);
1542 gen_op_iwmmxt_set_mup();
1543 gen_op_iwmmxt_set_cup();
1544 break;
1545 case 0x810: case 0xa10: /* WMADD */
1546 wrd = (insn >> 12) & 0xf;
1547 rd0 = (insn >> 0) & 0xf;
1548 rd1 = (insn >> 16) & 0xf;
1549 gen_op_iwmmxt_movq_M0_wRn(rd0);
1550 if (insn & (1 << 21))
1551 gen_op_iwmmxt_maddsq_M0_wRn(rd1);
1552 else
1553 gen_op_iwmmxt_madduq_M0_wRn(rd1);
1554 gen_op_iwmmxt_movq_wRn_M0(wrd);
1555 gen_op_iwmmxt_set_mup();
1556 break;
1557 case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */
1558 wrd = (insn >> 12) & 0xf;
1559 rd0 = (insn >> 16) & 0xf;
1560 rd1 = (insn >> 0) & 0xf;
1561 gen_op_iwmmxt_movq_M0_wRn(rd0);
1562 switch ((insn >> 22) & 3) {
1563 case 0:
1564 gen_op_iwmmxt_unpacklb_M0_wRn(rd1);
1565 break;
1566 case 1:
1567 gen_op_iwmmxt_unpacklw_M0_wRn(rd1);
1568 break;
1569 case 2:
1570 gen_op_iwmmxt_unpackll_M0_wRn(rd1);
1571 break;
1572 case 3:
1573 return 1;
1574 }
1575 gen_op_iwmmxt_movq_wRn_M0(wrd);
1576 gen_op_iwmmxt_set_mup();
1577 gen_op_iwmmxt_set_cup();
1578 break;
1579 case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */
1580 wrd = (insn >> 12) & 0xf;
1581 rd0 = (insn >> 16) & 0xf;
1582 rd1 = (insn >> 0) & 0xf;
1583 gen_op_iwmmxt_movq_M0_wRn(rd0);
1584 switch ((insn >> 22) & 3) {
1585 case 0:
1586 gen_op_iwmmxt_unpackhb_M0_wRn(rd1);
1587 break;
1588 case 1:
1589 gen_op_iwmmxt_unpackhw_M0_wRn(rd1);
1590 break;
1591 case 2:
1592 gen_op_iwmmxt_unpackhl_M0_wRn(rd1);
1593 break;
1594 case 3:
1595 return 1;
1596 }
1597 gen_op_iwmmxt_movq_wRn_M0(wrd);
1598 gen_op_iwmmxt_set_mup();
1599 gen_op_iwmmxt_set_cup();
1600 break;
1601 case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */
1602 wrd = (insn >> 12) & 0xf;
1603 rd0 = (insn >> 16) & 0xf;
1604 rd1 = (insn >> 0) & 0xf;
1605 gen_op_iwmmxt_movq_M0_wRn(rd0);
1606 if (insn & (1 << 22))
1607 gen_op_iwmmxt_sadw_M0_wRn(rd1);
1608 else
1609 gen_op_iwmmxt_sadb_M0_wRn(rd1);
1610 if (!(insn & (1 << 20)))
1611 gen_op_iwmmxt_addl_M0_wRn(wrd);
1612 gen_op_iwmmxt_movq_wRn_M0(wrd);
1613 gen_op_iwmmxt_set_mup();
1614 break;
1615 case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */
1616 wrd = (insn >> 12) & 0xf;
1617 rd0 = (insn >> 16) & 0xf;
1618 rd1 = (insn >> 0) & 0xf;
1619 gen_op_iwmmxt_movq_M0_wRn(rd0);
pbrooke6771372008-03-31 03:49:05 +00001620 if (insn & (1 << 21)) {
1621 if (insn & (1 << 20))
1622 gen_op_iwmmxt_mulshw_M0_wRn(rd1);
1623 else
1624 gen_op_iwmmxt_mulslw_M0_wRn(rd1);
1625 } else {
1626 if (insn & (1 << 20))
1627 gen_op_iwmmxt_muluhw_M0_wRn(rd1);
1628 else
1629 gen_op_iwmmxt_mululw_M0_wRn(rd1);
1630 }
balrog18c9b562007-04-30 02:02:17 +00001631 gen_op_iwmmxt_movq_wRn_M0(wrd);
1632 gen_op_iwmmxt_set_mup();
1633 break;
1634 case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */
1635 wrd = (insn >> 12) & 0xf;
1636 rd0 = (insn >> 16) & 0xf;
1637 rd1 = (insn >> 0) & 0xf;
1638 gen_op_iwmmxt_movq_M0_wRn(rd0);
1639 if (insn & (1 << 21))
1640 gen_op_iwmmxt_macsw_M0_wRn(rd1);
1641 else
1642 gen_op_iwmmxt_macuw_M0_wRn(rd1);
1643 if (!(insn & (1 << 20))) {
pbrooke6771372008-03-31 03:49:05 +00001644 iwmmxt_load_reg(cpu_V1, wrd);
1645 tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
balrog18c9b562007-04-30 02:02:17 +00001646 }
1647 gen_op_iwmmxt_movq_wRn_M0(wrd);
1648 gen_op_iwmmxt_set_mup();
1649 break;
1650 case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */
1651 wrd = (insn >> 12) & 0xf;
1652 rd0 = (insn >> 16) & 0xf;
1653 rd1 = (insn >> 0) & 0xf;
1654 gen_op_iwmmxt_movq_M0_wRn(rd0);
1655 switch ((insn >> 22) & 3) {
1656 case 0:
1657 gen_op_iwmmxt_cmpeqb_M0_wRn(rd1);
1658 break;
1659 case 1:
1660 gen_op_iwmmxt_cmpeqw_M0_wRn(rd1);
1661 break;
1662 case 2:
1663 gen_op_iwmmxt_cmpeql_M0_wRn(rd1);
1664 break;
1665 case 3:
1666 return 1;
1667 }
1668 gen_op_iwmmxt_movq_wRn_M0(wrd);
1669 gen_op_iwmmxt_set_mup();
1670 gen_op_iwmmxt_set_cup();
1671 break;
1672 case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */
1673 wrd = (insn >> 12) & 0xf;
1674 rd0 = (insn >> 16) & 0xf;
1675 rd1 = (insn >> 0) & 0xf;
1676 gen_op_iwmmxt_movq_M0_wRn(rd0);
pbrooke6771372008-03-31 03:49:05 +00001677 if (insn & (1 << 22)) {
1678 if (insn & (1 << 20))
1679 gen_op_iwmmxt_avgw1_M0_wRn(rd1);
1680 else
1681 gen_op_iwmmxt_avgw0_M0_wRn(rd1);
1682 } else {
1683 if (insn & (1 << 20))
1684 gen_op_iwmmxt_avgb1_M0_wRn(rd1);
1685 else
1686 gen_op_iwmmxt_avgb0_M0_wRn(rd1);
1687 }
balrog18c9b562007-04-30 02:02:17 +00001688 gen_op_iwmmxt_movq_wRn_M0(wrd);
1689 gen_op_iwmmxt_set_mup();
1690 gen_op_iwmmxt_set_cup();
1691 break;
1692 case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */
1693 wrd = (insn >> 12) & 0xf;
1694 rd0 = (insn >> 16) & 0xf;
1695 rd1 = (insn >> 0) & 0xf;
1696 gen_op_iwmmxt_movq_M0_wRn(rd0);
Filip Navarada6b5332009-10-15 14:39:02 +02001697 tmp = iwmmxt_load_creg(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
1698 tcg_gen_andi_i32(tmp, tmp, 7);
1699 iwmmxt_load_reg(cpu_V1, rd1);
1700 gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001701 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00001702 gen_op_iwmmxt_movq_wRn_M0(wrd);
1703 gen_op_iwmmxt_set_mup();
1704 break;
1705 case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */
Filip Navarada6b5332009-10-15 14:39:02 +02001706 if (((insn >> 6) & 3) == 3)
1707 return 1;
balrog18c9b562007-04-30 02:02:17 +00001708 rd = (insn >> 12) & 0xf;
1709 wrd = (insn >> 16) & 0xf;
Filip Navarada6b5332009-10-15 14:39:02 +02001710 tmp = load_reg(s, rd);
balrog18c9b562007-04-30 02:02:17 +00001711 gen_op_iwmmxt_movq_M0_wRn(wrd);
1712 switch ((insn >> 6) & 3) {
1713 case 0:
Filip Navarada6b5332009-10-15 14:39:02 +02001714 tmp2 = tcg_const_i32(0xff);
1715 tmp3 = tcg_const_i32((insn & 7) << 3);
balrog18c9b562007-04-30 02:02:17 +00001716 break;
1717 case 1:
Filip Navarada6b5332009-10-15 14:39:02 +02001718 tmp2 = tcg_const_i32(0xffff);
1719 tmp3 = tcg_const_i32((insn & 3) << 4);
balrog18c9b562007-04-30 02:02:17 +00001720 break;
1721 case 2:
Filip Navarada6b5332009-10-15 14:39:02 +02001722 tmp2 = tcg_const_i32(0xffffffff);
1723 tmp3 = tcg_const_i32((insn & 1) << 5);
balrog18c9b562007-04-30 02:02:17 +00001724 break;
Filip Navarada6b5332009-10-15 14:39:02 +02001725 default:
1726 TCGV_UNUSED(tmp2);
1727 TCGV_UNUSED(tmp3);
balrog18c9b562007-04-30 02:02:17 +00001728 }
Filip Navarada6b5332009-10-15 14:39:02 +02001729 gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3);
1730 tcg_temp_free(tmp3);
1731 tcg_temp_free(tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001732 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00001733 gen_op_iwmmxt_movq_wRn_M0(wrd);
1734 gen_op_iwmmxt_set_mup();
1735 break;
1736 case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */
1737 rd = (insn >> 12) & 0xf;
1738 wrd = (insn >> 16) & 0xf;
Filip Navarada6b5332009-10-15 14:39:02 +02001739 if (rd == 15 || ((insn >> 22) & 3) == 3)
balrog18c9b562007-04-30 02:02:17 +00001740 return 1;
1741 gen_op_iwmmxt_movq_M0_wRn(wrd);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001742 tmp = tcg_temp_new_i32();
balrog18c9b562007-04-30 02:02:17 +00001743 switch ((insn >> 22) & 3) {
1744 case 0:
Filip Navarada6b5332009-10-15 14:39:02 +02001745 tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3);
1746 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1747 if (insn & 8) {
1748 tcg_gen_ext8s_i32(tmp, tmp);
1749 } else {
1750 tcg_gen_andi_i32(tmp, tmp, 0xff);
balrog18c9b562007-04-30 02:02:17 +00001751 }
1752 break;
1753 case 1:
Filip Navarada6b5332009-10-15 14:39:02 +02001754 tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 3) << 4);
1755 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1756 if (insn & 8) {
1757 tcg_gen_ext16s_i32(tmp, tmp);
1758 } else {
1759 tcg_gen_andi_i32(tmp, tmp, 0xffff);
balrog18c9b562007-04-30 02:02:17 +00001760 }
1761 break;
1762 case 2:
Filip Navarada6b5332009-10-15 14:39:02 +02001763 tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 1) << 5);
1764 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001765 break;
balrog18c9b562007-04-30 02:02:17 +00001766 }
Filip Navarada6b5332009-10-15 14:39:02 +02001767 store_reg(s, rd, tmp);
balrog18c9b562007-04-30 02:02:17 +00001768 break;
1769 case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */
Filip Navarada6b5332009-10-15 14:39:02 +02001770 if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3)
balrog18c9b562007-04-30 02:02:17 +00001771 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02001772 tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
balrog18c9b562007-04-30 02:02:17 +00001773 switch ((insn >> 22) & 3) {
1774 case 0:
Filip Navarada6b5332009-10-15 14:39:02 +02001775 tcg_gen_shri_i32(tmp, tmp, ((insn & 7) << 2) + 0);
balrog18c9b562007-04-30 02:02:17 +00001776 break;
1777 case 1:
Filip Navarada6b5332009-10-15 14:39:02 +02001778 tcg_gen_shri_i32(tmp, tmp, ((insn & 3) << 3) + 4);
balrog18c9b562007-04-30 02:02:17 +00001779 break;
1780 case 2:
Filip Navarada6b5332009-10-15 14:39:02 +02001781 tcg_gen_shri_i32(tmp, tmp, ((insn & 1) << 4) + 12);
balrog18c9b562007-04-30 02:02:17 +00001782 break;
balrog18c9b562007-04-30 02:02:17 +00001783 }
Filip Navarada6b5332009-10-15 14:39:02 +02001784 tcg_gen_shli_i32(tmp, tmp, 28);
1785 gen_set_nzcv(tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001786 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00001787 break;
1788 case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */
Filip Navarada6b5332009-10-15 14:39:02 +02001789 if (((insn >> 6) & 3) == 3)
1790 return 1;
balrog18c9b562007-04-30 02:02:17 +00001791 rd = (insn >> 12) & 0xf;
1792 wrd = (insn >> 16) & 0xf;
Filip Navarada6b5332009-10-15 14:39:02 +02001793 tmp = load_reg(s, rd);
balrog18c9b562007-04-30 02:02:17 +00001794 switch ((insn >> 6) & 3) {
1795 case 0:
Filip Navarada6b5332009-10-15 14:39:02 +02001796 gen_helper_iwmmxt_bcstb(cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00001797 break;
1798 case 1:
Filip Navarada6b5332009-10-15 14:39:02 +02001799 gen_helper_iwmmxt_bcstw(cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00001800 break;
1801 case 2:
Filip Navarada6b5332009-10-15 14:39:02 +02001802 gen_helper_iwmmxt_bcstl(cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00001803 break;
balrog18c9b562007-04-30 02:02:17 +00001804 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00001805 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00001806 gen_op_iwmmxt_movq_wRn_M0(wrd);
1807 gen_op_iwmmxt_set_mup();
1808 break;
1809 case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */
Filip Navarada6b5332009-10-15 14:39:02 +02001810 if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
balrog18c9b562007-04-30 02:02:17 +00001811 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02001812 tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001813 tmp2 = tcg_temp_new_i32();
Filip Navarada6b5332009-10-15 14:39:02 +02001814 tcg_gen_mov_i32(tmp2, tmp);
balrog18c9b562007-04-30 02:02:17 +00001815 switch ((insn >> 22) & 3) {
1816 case 0:
1817 for (i = 0; i < 7; i ++) {
Filip Navarada6b5332009-10-15 14:39:02 +02001818 tcg_gen_shli_i32(tmp2, tmp2, 4);
1819 tcg_gen_and_i32(tmp, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00001820 }
1821 break;
1822 case 1:
1823 for (i = 0; i < 3; i ++) {
Filip Navarada6b5332009-10-15 14:39:02 +02001824 tcg_gen_shli_i32(tmp2, tmp2, 8);
1825 tcg_gen_and_i32(tmp, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00001826 }
1827 break;
1828 case 2:
Filip Navarada6b5332009-10-15 14:39:02 +02001829 tcg_gen_shli_i32(tmp2, tmp2, 16);
1830 tcg_gen_and_i32(tmp, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00001831 break;
balrog18c9b562007-04-30 02:02:17 +00001832 }
Filip Navarada6b5332009-10-15 14:39:02 +02001833 gen_set_nzcv(tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001834 tcg_temp_free_i32(tmp2);
1835 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00001836 break;
1837 case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */
1838 wrd = (insn >> 12) & 0xf;
1839 rd0 = (insn >> 16) & 0xf;
1840 gen_op_iwmmxt_movq_M0_wRn(rd0);
1841 switch ((insn >> 22) & 3) {
1842 case 0:
pbrooke6771372008-03-31 03:49:05 +00001843 gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001844 break;
1845 case 1:
pbrooke6771372008-03-31 03:49:05 +00001846 gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001847 break;
1848 case 2:
pbrooke6771372008-03-31 03:49:05 +00001849 gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001850 break;
1851 case 3:
1852 return 1;
1853 }
1854 gen_op_iwmmxt_movq_wRn_M0(wrd);
1855 gen_op_iwmmxt_set_mup();
1856 break;
1857 case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */
Filip Navarada6b5332009-10-15 14:39:02 +02001858 if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
balrog18c9b562007-04-30 02:02:17 +00001859 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02001860 tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001861 tmp2 = tcg_temp_new_i32();
Filip Navarada6b5332009-10-15 14:39:02 +02001862 tcg_gen_mov_i32(tmp2, tmp);
balrog18c9b562007-04-30 02:02:17 +00001863 switch ((insn >> 22) & 3) {
1864 case 0:
1865 for (i = 0; i < 7; i ++) {
Filip Navarada6b5332009-10-15 14:39:02 +02001866 tcg_gen_shli_i32(tmp2, tmp2, 4);
1867 tcg_gen_or_i32(tmp, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00001868 }
1869 break;
1870 case 1:
1871 for (i = 0; i < 3; i ++) {
Filip Navarada6b5332009-10-15 14:39:02 +02001872 tcg_gen_shli_i32(tmp2, tmp2, 8);
1873 tcg_gen_or_i32(tmp, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00001874 }
1875 break;
1876 case 2:
Filip Navarada6b5332009-10-15 14:39:02 +02001877 tcg_gen_shli_i32(tmp2, tmp2, 16);
1878 tcg_gen_or_i32(tmp, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00001879 break;
balrog18c9b562007-04-30 02:02:17 +00001880 }
Filip Navarada6b5332009-10-15 14:39:02 +02001881 gen_set_nzcv(tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001882 tcg_temp_free_i32(tmp2);
1883 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00001884 break;
1885 case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */
1886 rd = (insn >> 12) & 0xf;
1887 rd0 = (insn >> 16) & 0xf;
Filip Navarada6b5332009-10-15 14:39:02 +02001888 if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
balrog18c9b562007-04-30 02:02:17 +00001889 return 1;
1890 gen_op_iwmmxt_movq_M0_wRn(rd0);
Peter Maydell7d1b0092011-03-06 21:39:54 +00001891 tmp = tcg_temp_new_i32();
balrog18c9b562007-04-30 02:02:17 +00001892 switch ((insn >> 22) & 3) {
1893 case 0:
Filip Navarada6b5332009-10-15 14:39:02 +02001894 gen_helper_iwmmxt_msbb(tmp, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001895 break;
1896 case 1:
Filip Navarada6b5332009-10-15 14:39:02 +02001897 gen_helper_iwmmxt_msbw(tmp, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001898 break;
1899 case 2:
Filip Navarada6b5332009-10-15 14:39:02 +02001900 gen_helper_iwmmxt_msbl(tmp, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001901 break;
balrog18c9b562007-04-30 02:02:17 +00001902 }
Filip Navarada6b5332009-10-15 14:39:02 +02001903 store_reg(s, rd, tmp);
balrog18c9b562007-04-30 02:02:17 +00001904 break;
1905 case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */
1906 case 0x906: case 0xb06: case 0xd06: case 0xf06:
1907 wrd = (insn >> 12) & 0xf;
1908 rd0 = (insn >> 16) & 0xf;
1909 rd1 = (insn >> 0) & 0xf;
1910 gen_op_iwmmxt_movq_M0_wRn(rd0);
1911 switch ((insn >> 22) & 3) {
1912 case 0:
1913 if (insn & (1 << 21))
1914 gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1);
1915 else
1916 gen_op_iwmmxt_cmpgtub_M0_wRn(rd1);
1917 break;
1918 case 1:
1919 if (insn & (1 << 21))
1920 gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1);
1921 else
1922 gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1);
1923 break;
1924 case 2:
1925 if (insn & (1 << 21))
1926 gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1);
1927 else
1928 gen_op_iwmmxt_cmpgtul_M0_wRn(rd1);
1929 break;
1930 case 3:
1931 return 1;
1932 }
1933 gen_op_iwmmxt_movq_wRn_M0(wrd);
1934 gen_op_iwmmxt_set_mup();
1935 gen_op_iwmmxt_set_cup();
1936 break;
1937 case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */
1938 case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
1939 wrd = (insn >> 12) & 0xf;
1940 rd0 = (insn >> 16) & 0xf;
1941 gen_op_iwmmxt_movq_M0_wRn(rd0);
1942 switch ((insn >> 22) & 3) {
1943 case 0:
1944 if (insn & (1 << 21))
1945 gen_op_iwmmxt_unpacklsb_M0();
1946 else
1947 gen_op_iwmmxt_unpacklub_M0();
1948 break;
1949 case 1:
1950 if (insn & (1 << 21))
1951 gen_op_iwmmxt_unpacklsw_M0();
1952 else
1953 gen_op_iwmmxt_unpackluw_M0();
1954 break;
1955 case 2:
1956 if (insn & (1 << 21))
1957 gen_op_iwmmxt_unpacklsl_M0();
1958 else
1959 gen_op_iwmmxt_unpacklul_M0();
1960 break;
1961 case 3:
1962 return 1;
1963 }
1964 gen_op_iwmmxt_movq_wRn_M0(wrd);
1965 gen_op_iwmmxt_set_mup();
1966 gen_op_iwmmxt_set_cup();
1967 break;
1968 case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */
1969 case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
1970 wrd = (insn >> 12) & 0xf;
1971 rd0 = (insn >> 16) & 0xf;
1972 gen_op_iwmmxt_movq_M0_wRn(rd0);
1973 switch ((insn >> 22) & 3) {
1974 case 0:
1975 if (insn & (1 << 21))
1976 gen_op_iwmmxt_unpackhsb_M0();
1977 else
1978 gen_op_iwmmxt_unpackhub_M0();
1979 break;
1980 case 1:
1981 if (insn & (1 << 21))
1982 gen_op_iwmmxt_unpackhsw_M0();
1983 else
1984 gen_op_iwmmxt_unpackhuw_M0();
1985 break;
1986 case 2:
1987 if (insn & (1 << 21))
1988 gen_op_iwmmxt_unpackhsl_M0();
1989 else
1990 gen_op_iwmmxt_unpackhul_M0();
1991 break;
1992 case 3:
1993 return 1;
1994 }
1995 gen_op_iwmmxt_movq_wRn_M0(wrd);
1996 gen_op_iwmmxt_set_mup();
1997 gen_op_iwmmxt_set_cup();
1998 break;
1999 case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */
2000 case 0x214: case 0x614: case 0xa14: case 0xe14:
Filip Navarada6b5332009-10-15 14:39:02 +02002001 if (((insn >> 22) & 3) == 0)
2002 return 1;
balrog18c9b562007-04-30 02:02:17 +00002003 wrd = (insn >> 12) & 0xf;
2004 rd0 = (insn >> 16) & 0xf;
2005 gen_op_iwmmxt_movq_M0_wRn(rd0);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002006 tmp = tcg_temp_new_i32();
Filip Navarada6b5332009-10-15 14:39:02 +02002007 if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00002008 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002009 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02002010 }
balrog18c9b562007-04-30 02:02:17 +00002011 switch ((insn >> 22) & 3) {
balrog18c9b562007-04-30 02:02:17 +00002012 case 1:
Peter Maydell477955b2011-05-25 13:22:31 +00002013 gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002014 break;
2015 case 2:
Peter Maydell477955b2011-05-25 13:22:31 +00002016 gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002017 break;
2018 case 3:
Peter Maydell477955b2011-05-25 13:22:31 +00002019 gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002020 break;
2021 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00002022 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002023 gen_op_iwmmxt_movq_wRn_M0(wrd);
2024 gen_op_iwmmxt_set_mup();
2025 gen_op_iwmmxt_set_cup();
2026 break;
2027 case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */
2028 case 0x014: case 0x414: case 0x814: case 0xc14:
Filip Navarada6b5332009-10-15 14:39:02 +02002029 if (((insn >> 22) & 3) == 0)
2030 return 1;
balrog18c9b562007-04-30 02:02:17 +00002031 wrd = (insn >> 12) & 0xf;
2032 rd0 = (insn >> 16) & 0xf;
2033 gen_op_iwmmxt_movq_M0_wRn(rd0);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002034 tmp = tcg_temp_new_i32();
Filip Navarada6b5332009-10-15 14:39:02 +02002035 if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00002036 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002037 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02002038 }
balrog18c9b562007-04-30 02:02:17 +00002039 switch ((insn >> 22) & 3) {
balrog18c9b562007-04-30 02:02:17 +00002040 case 1:
Peter Maydell477955b2011-05-25 13:22:31 +00002041 gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002042 break;
2043 case 2:
Peter Maydell477955b2011-05-25 13:22:31 +00002044 gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002045 break;
2046 case 3:
Peter Maydell477955b2011-05-25 13:22:31 +00002047 gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002048 break;
2049 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00002050 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002051 gen_op_iwmmxt_movq_wRn_M0(wrd);
2052 gen_op_iwmmxt_set_mup();
2053 gen_op_iwmmxt_set_cup();
2054 break;
2055 case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */
2056 case 0x114: case 0x514: case 0x914: case 0xd14:
Filip Navarada6b5332009-10-15 14:39:02 +02002057 if (((insn >> 22) & 3) == 0)
2058 return 1;
balrog18c9b562007-04-30 02:02:17 +00002059 wrd = (insn >> 12) & 0xf;
2060 rd0 = (insn >> 16) & 0xf;
2061 gen_op_iwmmxt_movq_M0_wRn(rd0);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002062 tmp = tcg_temp_new_i32();
Filip Navarada6b5332009-10-15 14:39:02 +02002063 if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00002064 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002065 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02002066 }
balrog18c9b562007-04-30 02:02:17 +00002067 switch ((insn >> 22) & 3) {
balrog18c9b562007-04-30 02:02:17 +00002068 case 1:
Peter Maydell477955b2011-05-25 13:22:31 +00002069 gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002070 break;
2071 case 2:
Peter Maydell477955b2011-05-25 13:22:31 +00002072 gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002073 break;
2074 case 3:
Peter Maydell477955b2011-05-25 13:22:31 +00002075 gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002076 break;
2077 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00002078 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002079 gen_op_iwmmxt_movq_wRn_M0(wrd);
2080 gen_op_iwmmxt_set_mup();
2081 gen_op_iwmmxt_set_cup();
2082 break;
2083 case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */
2084 case 0x314: case 0x714: case 0xb14: case 0xf14:
Filip Navarada6b5332009-10-15 14:39:02 +02002085 if (((insn >> 22) & 3) == 0)
2086 return 1;
balrog18c9b562007-04-30 02:02:17 +00002087 wrd = (insn >> 12) & 0xf;
2088 rd0 = (insn >> 16) & 0xf;
2089 gen_op_iwmmxt_movq_M0_wRn(rd0);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002090 tmp = tcg_temp_new_i32();
balrog18c9b562007-04-30 02:02:17 +00002091 switch ((insn >> 22) & 3) {
balrog18c9b562007-04-30 02:02:17 +00002092 case 1:
Filip Navarada6b5332009-10-15 14:39:02 +02002093 if (gen_iwmmxt_shift(insn, 0xf, tmp)) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00002094 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002095 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02002096 }
Peter Maydell477955b2011-05-25 13:22:31 +00002097 gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002098 break;
2099 case 2:
Filip Navarada6b5332009-10-15 14:39:02 +02002100 if (gen_iwmmxt_shift(insn, 0x1f, tmp)) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00002101 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002102 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02002103 }
Peter Maydell477955b2011-05-25 13:22:31 +00002104 gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002105 break;
2106 case 3:
Filip Navarada6b5332009-10-15 14:39:02 +02002107 if (gen_iwmmxt_shift(insn, 0x3f, tmp)) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00002108 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002109 return 1;
Filip Navarada6b5332009-10-15 14:39:02 +02002110 }
Peter Maydell477955b2011-05-25 13:22:31 +00002111 gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp);
balrog18c9b562007-04-30 02:02:17 +00002112 break;
2113 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00002114 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002115 gen_op_iwmmxt_movq_wRn_M0(wrd);
2116 gen_op_iwmmxt_set_mup();
2117 gen_op_iwmmxt_set_cup();
2118 break;
2119 case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */
2120 case 0x916: case 0xb16: case 0xd16: case 0xf16:
2121 wrd = (insn >> 12) & 0xf;
2122 rd0 = (insn >> 16) & 0xf;
2123 rd1 = (insn >> 0) & 0xf;
2124 gen_op_iwmmxt_movq_M0_wRn(rd0);
2125 switch ((insn >> 22) & 3) {
2126 case 0:
2127 if (insn & (1 << 21))
2128 gen_op_iwmmxt_minsb_M0_wRn(rd1);
2129 else
2130 gen_op_iwmmxt_minub_M0_wRn(rd1);
2131 break;
2132 case 1:
2133 if (insn & (1 << 21))
2134 gen_op_iwmmxt_minsw_M0_wRn(rd1);
2135 else
2136 gen_op_iwmmxt_minuw_M0_wRn(rd1);
2137 break;
2138 case 2:
2139 if (insn & (1 << 21))
2140 gen_op_iwmmxt_minsl_M0_wRn(rd1);
2141 else
2142 gen_op_iwmmxt_minul_M0_wRn(rd1);
2143 break;
2144 case 3:
2145 return 1;
2146 }
2147 gen_op_iwmmxt_movq_wRn_M0(wrd);
2148 gen_op_iwmmxt_set_mup();
2149 break;
2150 case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */
2151 case 0x816: case 0xa16: case 0xc16: case 0xe16:
2152 wrd = (insn >> 12) & 0xf;
2153 rd0 = (insn >> 16) & 0xf;
2154 rd1 = (insn >> 0) & 0xf;
2155 gen_op_iwmmxt_movq_M0_wRn(rd0);
2156 switch ((insn >> 22) & 3) {
2157 case 0:
2158 if (insn & (1 << 21))
2159 gen_op_iwmmxt_maxsb_M0_wRn(rd1);
2160 else
2161 gen_op_iwmmxt_maxub_M0_wRn(rd1);
2162 break;
2163 case 1:
2164 if (insn & (1 << 21))
2165 gen_op_iwmmxt_maxsw_M0_wRn(rd1);
2166 else
2167 gen_op_iwmmxt_maxuw_M0_wRn(rd1);
2168 break;
2169 case 2:
2170 if (insn & (1 << 21))
2171 gen_op_iwmmxt_maxsl_M0_wRn(rd1);
2172 else
2173 gen_op_iwmmxt_maxul_M0_wRn(rd1);
2174 break;
2175 case 3:
2176 return 1;
2177 }
2178 gen_op_iwmmxt_movq_wRn_M0(wrd);
2179 gen_op_iwmmxt_set_mup();
2180 break;
2181 case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */
2182 case 0x402: case 0x502: case 0x602: case 0x702:
2183 wrd = (insn >> 12) & 0xf;
2184 rd0 = (insn >> 16) & 0xf;
2185 rd1 = (insn >> 0) & 0xf;
2186 gen_op_iwmmxt_movq_M0_wRn(rd0);
Filip Navarada6b5332009-10-15 14:39:02 +02002187 tmp = tcg_const_i32((insn >> 20) & 3);
2188 iwmmxt_load_reg(cpu_V1, rd1);
2189 gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
2190 tcg_temp_free(tmp);
balrog18c9b562007-04-30 02:02:17 +00002191 gen_op_iwmmxt_movq_wRn_M0(wrd);
2192 gen_op_iwmmxt_set_mup();
2193 break;
2194 case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */
2195 case 0x41a: case 0x51a: case 0x61a: case 0x71a:
2196 case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
2197 case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
2198 wrd = (insn >> 12) & 0xf;
2199 rd0 = (insn >> 16) & 0xf;
2200 rd1 = (insn >> 0) & 0xf;
2201 gen_op_iwmmxt_movq_M0_wRn(rd0);
2202 switch ((insn >> 20) & 0xf) {
2203 case 0x0:
2204 gen_op_iwmmxt_subnb_M0_wRn(rd1);
2205 break;
2206 case 0x1:
2207 gen_op_iwmmxt_subub_M0_wRn(rd1);
2208 break;
2209 case 0x3:
2210 gen_op_iwmmxt_subsb_M0_wRn(rd1);
2211 break;
2212 case 0x4:
2213 gen_op_iwmmxt_subnw_M0_wRn(rd1);
2214 break;
2215 case 0x5:
2216 gen_op_iwmmxt_subuw_M0_wRn(rd1);
2217 break;
2218 case 0x7:
2219 gen_op_iwmmxt_subsw_M0_wRn(rd1);
2220 break;
2221 case 0x8:
2222 gen_op_iwmmxt_subnl_M0_wRn(rd1);
2223 break;
2224 case 0x9:
2225 gen_op_iwmmxt_subul_M0_wRn(rd1);
2226 break;
2227 case 0xb:
2228 gen_op_iwmmxt_subsl_M0_wRn(rd1);
2229 break;
2230 default:
2231 return 1;
2232 }
2233 gen_op_iwmmxt_movq_wRn_M0(wrd);
2234 gen_op_iwmmxt_set_mup();
2235 gen_op_iwmmxt_set_cup();
2236 break;
2237 case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */
2238 case 0x41e: case 0x51e: case 0x61e: case 0x71e:
2239 case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
2240 case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
2241 wrd = (insn >> 12) & 0xf;
2242 rd0 = (insn >> 16) & 0xf;
2243 gen_op_iwmmxt_movq_M0_wRn(rd0);
Filip Navarada6b5332009-10-15 14:39:02 +02002244 tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f));
Peter Maydell477955b2011-05-25 13:22:31 +00002245 gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp);
Filip Navarada6b5332009-10-15 14:39:02 +02002246 tcg_temp_free(tmp);
balrog18c9b562007-04-30 02:02:17 +00002247 gen_op_iwmmxt_movq_wRn_M0(wrd);
2248 gen_op_iwmmxt_set_mup();
2249 gen_op_iwmmxt_set_cup();
2250 break;
2251 case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */
2252 case 0x418: case 0x518: case 0x618: case 0x718:
2253 case 0x818: case 0x918: case 0xa18: case 0xb18:
2254 case 0xc18: case 0xd18: case 0xe18: case 0xf18:
2255 wrd = (insn >> 12) & 0xf;
2256 rd0 = (insn >> 16) & 0xf;
2257 rd1 = (insn >> 0) & 0xf;
2258 gen_op_iwmmxt_movq_M0_wRn(rd0);
2259 switch ((insn >> 20) & 0xf) {
2260 case 0x0:
2261 gen_op_iwmmxt_addnb_M0_wRn(rd1);
2262 break;
2263 case 0x1:
2264 gen_op_iwmmxt_addub_M0_wRn(rd1);
2265 break;
2266 case 0x3:
2267 gen_op_iwmmxt_addsb_M0_wRn(rd1);
2268 break;
2269 case 0x4:
2270 gen_op_iwmmxt_addnw_M0_wRn(rd1);
2271 break;
2272 case 0x5:
2273 gen_op_iwmmxt_adduw_M0_wRn(rd1);
2274 break;
2275 case 0x7:
2276 gen_op_iwmmxt_addsw_M0_wRn(rd1);
2277 break;
2278 case 0x8:
2279 gen_op_iwmmxt_addnl_M0_wRn(rd1);
2280 break;
2281 case 0x9:
2282 gen_op_iwmmxt_addul_M0_wRn(rd1);
2283 break;
2284 case 0xb:
2285 gen_op_iwmmxt_addsl_M0_wRn(rd1);
2286 break;
2287 default:
2288 return 1;
2289 }
2290 gen_op_iwmmxt_movq_wRn_M0(wrd);
2291 gen_op_iwmmxt_set_mup();
2292 gen_op_iwmmxt_set_cup();
2293 break;
2294 case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */
2295 case 0x408: case 0x508: case 0x608: case 0x708:
2296 case 0x808: case 0x908: case 0xa08: case 0xb08:
2297 case 0xc08: case 0xd08: case 0xe08: case 0xf08:
Filip Navarada6b5332009-10-15 14:39:02 +02002298 if (!(insn & (1 << 20)) || ((insn >> 22) & 3) == 0)
2299 return 1;
balrog18c9b562007-04-30 02:02:17 +00002300 wrd = (insn >> 12) & 0xf;
2301 rd0 = (insn >> 16) & 0xf;
2302 rd1 = (insn >> 0) & 0xf;
2303 gen_op_iwmmxt_movq_M0_wRn(rd0);
balrog18c9b562007-04-30 02:02:17 +00002304 switch ((insn >> 22) & 3) {
balrog18c9b562007-04-30 02:02:17 +00002305 case 1:
2306 if (insn & (1 << 21))
2307 gen_op_iwmmxt_packsw_M0_wRn(rd1);
2308 else
2309 gen_op_iwmmxt_packuw_M0_wRn(rd1);
2310 break;
2311 case 2:
2312 if (insn & (1 << 21))
2313 gen_op_iwmmxt_packsl_M0_wRn(rd1);
2314 else
2315 gen_op_iwmmxt_packul_M0_wRn(rd1);
2316 break;
2317 case 3:
2318 if (insn & (1 << 21))
2319 gen_op_iwmmxt_packsq_M0_wRn(rd1);
2320 else
2321 gen_op_iwmmxt_packuq_M0_wRn(rd1);
2322 break;
2323 }
2324 gen_op_iwmmxt_movq_wRn_M0(wrd);
2325 gen_op_iwmmxt_set_mup();
2326 gen_op_iwmmxt_set_cup();
2327 break;
2328 case 0x201: case 0x203: case 0x205: case 0x207:
2329 case 0x209: case 0x20b: case 0x20d: case 0x20f:
2330 case 0x211: case 0x213: case 0x215: case 0x217:
2331 case 0x219: case 0x21b: case 0x21d: case 0x21f:
2332 wrd = (insn >> 5) & 0xf;
2333 rd0 = (insn >> 12) & 0xf;
2334 rd1 = (insn >> 0) & 0xf;
2335 if (rd0 == 0xf || rd1 == 0xf)
2336 return 1;
2337 gen_op_iwmmxt_movq_M0_wRn(wrd);
Filip Navarada6b5332009-10-15 14:39:02 +02002338 tmp = load_reg(s, rd0);
2339 tmp2 = load_reg(s, rd1);
balrog18c9b562007-04-30 02:02:17 +00002340 switch ((insn >> 16) & 0xf) {
2341 case 0x0: /* TMIA */
Filip Navarada6b5332009-10-15 14:39:02 +02002342 gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00002343 break;
2344 case 0x8: /* TMIAPH */
Filip Navarada6b5332009-10-15 14:39:02 +02002345 gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00002346 break;
2347 case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */
balrog18c9b562007-04-30 02:02:17 +00002348 if (insn & (1 << 16))
Filip Navarada6b5332009-10-15 14:39:02 +02002349 tcg_gen_shri_i32(tmp, tmp, 16);
balrog18c9b562007-04-30 02:02:17 +00002350 if (insn & (1 << 17))
Filip Navarada6b5332009-10-15 14:39:02 +02002351 tcg_gen_shri_i32(tmp2, tmp2, 16);
2352 gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00002353 break;
2354 default:
Peter Maydell7d1b0092011-03-06 21:39:54 +00002355 tcg_temp_free_i32(tmp2);
2356 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002357 return 1;
2358 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00002359 tcg_temp_free_i32(tmp2);
2360 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002361 gen_op_iwmmxt_movq_wRn_M0(wrd);
2362 gen_op_iwmmxt_set_mup();
2363 break;
2364 default:
2365 return 1;
2366 }
2367
2368 return 0;
2369}
2370
Stefan Weila1c72732011-04-28 17:20:38 +02002371/* Disassemble an XScale DSP instruction. Returns nonzero if an error occurred
balrog18c9b562007-04-30 02:02:17 +00002372 (ie. an undefined instruction). */
2373static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
2374{
2375 int acc, rd0, rd1, rdhi, rdlo;
Filip Navara3a554c02009-10-15 14:38:54 +02002376 TCGv tmp, tmp2;
balrog18c9b562007-04-30 02:02:17 +00002377
2378 if ((insn & 0x0ff00f10) == 0x0e200010) {
2379 /* Multiply with Internal Accumulate Format */
2380 rd0 = (insn >> 12) & 0xf;
2381 rd1 = insn & 0xf;
2382 acc = (insn >> 5) & 7;
2383
2384 if (acc != 0)
2385 return 1;
2386
Filip Navara3a554c02009-10-15 14:38:54 +02002387 tmp = load_reg(s, rd0);
2388 tmp2 = load_reg(s, rd1);
balrog18c9b562007-04-30 02:02:17 +00002389 switch ((insn >> 16) & 0xf) {
2390 case 0x0: /* MIA */
Filip Navara3a554c02009-10-15 14:38:54 +02002391 gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00002392 break;
2393 case 0x8: /* MIAPH */
Filip Navara3a554c02009-10-15 14:38:54 +02002394 gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00002395 break;
2396 case 0xc: /* MIABB */
2397 case 0xd: /* MIABT */
2398 case 0xe: /* MIATB */
2399 case 0xf: /* MIATT */
balrog18c9b562007-04-30 02:02:17 +00002400 if (insn & (1 << 16))
Filip Navara3a554c02009-10-15 14:38:54 +02002401 tcg_gen_shri_i32(tmp, tmp, 16);
balrog18c9b562007-04-30 02:02:17 +00002402 if (insn & (1 << 17))
Filip Navara3a554c02009-10-15 14:38:54 +02002403 tcg_gen_shri_i32(tmp2, tmp2, 16);
2404 gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
balrog18c9b562007-04-30 02:02:17 +00002405 break;
2406 default:
2407 return 1;
2408 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00002409 tcg_temp_free_i32(tmp2);
2410 tcg_temp_free_i32(tmp);
balrog18c9b562007-04-30 02:02:17 +00002411
2412 gen_op_iwmmxt_movq_wRn_M0(acc);
2413 return 0;
2414 }
2415
2416 if ((insn & 0x0fe00ff8) == 0x0c400000) {
2417 /* Internal Accumulator Access Format */
2418 rdhi = (insn >> 16) & 0xf;
2419 rdlo = (insn >> 12) & 0xf;
2420 acc = insn & 7;
2421
2422 if (acc != 0)
2423 return 1;
2424
2425 if (insn & ARM_CP_RW_BIT) { /* MRA */
Filip Navara3a554c02009-10-15 14:38:54 +02002426 iwmmxt_load_reg(cpu_V0, acc);
2427 tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0);
2428 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
2429 tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0);
2430 tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1);
balrog18c9b562007-04-30 02:02:17 +00002431 } else { /* MAR */
Filip Navara3a554c02009-10-15 14:38:54 +02002432 tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
2433 iwmmxt_store_reg(cpu_V0, acc);
balrog18c9b562007-04-30 02:02:17 +00002434 }
2435 return 0;
2436 }
2437
2438 return 1;
2439}
2440
balrogc1713132007-04-30 01:26:42 +00002441/* Disassemble system coprocessor instruction. Return nonzero if
2442 instruction is not defined. */
2443static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
2444{
Juha Riihimäkib75263d2009-10-22 15:17:36 +03002445 TCGv tmp, tmp2;
balrogc1713132007-04-30 01:26:42 +00002446 uint32_t rd = (insn >> 12) & 0xf;
2447 uint32_t cp = (insn >> 8) & 0xf;
2448 if (IS_USER(s)) {
2449 return 1;
2450 }
2451
balrog18c9b562007-04-30 02:02:17 +00002452 if (insn & ARM_CP_RW_BIT) {
balrogc1713132007-04-30 01:26:42 +00002453 if (!env->cp[cp].cp_read)
2454 return 1;
pbrook8984bd22008-03-31 03:47:48 +00002455 gen_set_pc_im(s->pc);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002456 tmp = tcg_temp_new_i32();
Juha Riihimäkib75263d2009-10-22 15:17:36 +03002457 tmp2 = tcg_const_i32(insn);
2458 gen_helper_get_cp(tmp, cpu_env, tmp2);
2459 tcg_temp_free(tmp2);
pbrook8984bd22008-03-31 03:47:48 +00002460 store_reg(s, rd, tmp);
balrogc1713132007-04-30 01:26:42 +00002461 } else {
2462 if (!env->cp[cp].cp_write)
2463 return 1;
pbrook8984bd22008-03-31 03:47:48 +00002464 gen_set_pc_im(s->pc);
2465 tmp = load_reg(s, rd);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03002466 tmp2 = tcg_const_i32(insn);
2467 gen_helper_set_cp(cpu_env, tmp2, tmp);
2468 tcg_temp_free(tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002469 tcg_temp_free_i32(tmp);
balrogc1713132007-04-30 01:26:42 +00002470 }
2471 return 0;
2472}
2473
Peter Maydell74594c92011-03-22 12:16:16 +00002474static int cp15_user_ok(CPUState *env, uint32_t insn)
pbrook9ee6e8b2007-11-11 00:04:49 +00002475{
2476 int cpn = (insn >> 16) & 0xf;
2477 int cpm = insn & 0xf;
2478 int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);
2479
Peter Maydell74594c92011-03-22 12:16:16 +00002480 if (arm_feature(env, ARM_FEATURE_V7) && cpn == 9) {
2481 /* Performance monitor registers fall into three categories:
2482 * (a) always UNDEF in usermode
2483 * (b) UNDEF only if PMUSERENR.EN is 0
2484 * (c) always read OK and UNDEF on write (PMUSERENR only)
2485 */
2486 if ((cpm == 12 && (op < 6)) ||
2487 (cpm == 13 && (op < 3))) {
2488 return env->cp15.c9_pmuserenr;
2489 } else if (cpm == 14 && op == 0 && (insn & ARM_CP_RW_BIT)) {
2490 /* PMUSERENR, read only */
2491 return 1;
2492 }
2493 return 0;
2494 }
2495
pbrook9ee6e8b2007-11-11 00:04:49 +00002496 if (cpn == 13 && cpm == 0) {
2497 /* TLS register. */
2498 if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT)))
2499 return 1;
2500 }
pbrook9ee6e8b2007-11-11 00:04:49 +00002501 return 0;
2502}
2503
Riku Voipio3f26c122010-01-25 15:17:32 +02002504static int cp15_tls_load_store(CPUState *env, DisasContext *s, uint32_t insn, uint32_t rd)
2505{
2506 TCGv tmp;
2507 int cpn = (insn >> 16) & 0xf;
2508 int cpm = insn & 0xf;
2509 int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);
2510
2511 if (!arm_feature(env, ARM_FEATURE_V6K))
2512 return 0;
2513
2514 if (!(cpn == 13 && cpm == 0))
2515 return 0;
2516
2517 if (insn & ARM_CP_RW_BIT) {
Riku Voipio3f26c122010-01-25 15:17:32 +02002518 switch (op) {
2519 case 2:
Paul Brookc5883be2010-02-23 14:45:16 +00002520 tmp = load_cpu_field(cp15.c13_tls1);
Riku Voipio3f26c122010-01-25 15:17:32 +02002521 break;
2522 case 3:
Paul Brookc5883be2010-02-23 14:45:16 +00002523 tmp = load_cpu_field(cp15.c13_tls2);
Riku Voipio3f26c122010-01-25 15:17:32 +02002524 break;
2525 case 4:
Paul Brookc5883be2010-02-23 14:45:16 +00002526 tmp = load_cpu_field(cp15.c13_tls3);
Riku Voipio3f26c122010-01-25 15:17:32 +02002527 break;
2528 default:
Riku Voipio3f26c122010-01-25 15:17:32 +02002529 return 0;
2530 }
2531 store_reg(s, rd, tmp);
2532
2533 } else {
2534 tmp = load_reg(s, rd);
2535 switch (op) {
2536 case 2:
Paul Brookc5883be2010-02-23 14:45:16 +00002537 store_cpu_field(tmp, cp15.c13_tls1);
Riku Voipio3f26c122010-01-25 15:17:32 +02002538 break;
2539 case 3:
Paul Brookc5883be2010-02-23 14:45:16 +00002540 store_cpu_field(tmp, cp15.c13_tls2);
Riku Voipio3f26c122010-01-25 15:17:32 +02002541 break;
2542 case 4:
Paul Brookc5883be2010-02-23 14:45:16 +00002543 store_cpu_field(tmp, cp15.c13_tls3);
Riku Voipio3f26c122010-01-25 15:17:32 +02002544 break;
2545 default:
Peter Maydell7d1b0092011-03-06 21:39:54 +00002546 tcg_temp_free_i32(tmp);
Riku Voipio3f26c122010-01-25 15:17:32 +02002547 return 0;
2548 }
Riku Voipio3f26c122010-01-25 15:17:32 +02002549 }
2550 return 1;
2551}
2552
bellardb5ff1b32005-11-26 10:38:39 +00002553/* Disassemble system coprocessor (cp15) instruction. Return nonzero if
2554 instruction is not defined. */
balroga90b7312007-05-01 01:28:01 +00002555static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
bellardb5ff1b32005-11-26 10:38:39 +00002556{
2557 uint32_t rd;
Juha Riihimäkib75263d2009-10-22 15:17:36 +03002558 TCGv tmp, tmp2;
bellardb5ff1b32005-11-26 10:38:39 +00002559
pbrook9ee6e8b2007-11-11 00:04:49 +00002560 /* M profile cores use memory mapped registers instead of cp15. */
2561 if (arm_feature(env, ARM_FEATURE_M))
2562 return 1;
2563
2564 if ((insn & (1 << 25)) == 0) {
2565 if (insn & (1 << 20)) {
2566 /* mrrc */
2567 return 1;
2568 }
2569 /* mcrr. Used for block cache operations, so implement as no-op. */
2570 return 0;
2571 }
2572 if ((insn & (1 << 4)) == 0) {
2573 /* cdp */
2574 return 1;
2575 }
Peter Maydell87f19eb2011-07-21 07:01:51 +00002576 /* We special case a number of cp15 instructions which were used
2577 * for things which are real instructions in ARMv7. This allows
2578 * them to work in linux-user mode which doesn't provide functional
2579 * get_cp15/set_cp15 helpers, and is more efficient anyway.
Peter Maydellcc688902011-02-25 15:04:12 +00002580 */
Peter Maydell87f19eb2011-07-21 07:01:51 +00002581 switch ((insn & 0x0fff0fff)) {
2582 case 0x0e070f90:
Peter Maydellcc688902011-02-25 15:04:12 +00002583 /* 0,c7,c0,4: Standard v6 WFI (also used in some pre-v6 cores).
2584 * In v7, this must NOP.
2585 */
Peter Maydell87f19eb2011-07-21 07:01:51 +00002586 if (IS_USER(s)) {
2587 return 1;
2588 }
Peter Maydellcc688902011-02-25 15:04:12 +00002589 if (!arm_feature(env, ARM_FEATURE_V7)) {
2590 /* Wait for interrupt. */
2591 gen_set_pc_im(s->pc);
2592 s->is_jmp = DISAS_WFI;
2593 }
bellard9332f9d2005-11-26 10:46:39 +00002594 return 0;
Peter Maydell87f19eb2011-07-21 07:01:51 +00002595 case 0x0e070f58:
Peter Maydellcc688902011-02-25 15:04:12 +00002596 /* 0,c7,c8,2: Not all pre-v6 cores implemented this WFI,
2597 * so this is slightly over-broad.
2598 */
Peter Maydell87f19eb2011-07-21 07:01:51 +00002599 if (!IS_USER(s) && !arm_feature(env, ARM_FEATURE_V6)) {
Peter Maydellcc688902011-02-25 15:04:12 +00002600 /* Wait for interrupt. */
2601 gen_set_pc_im(s->pc);
2602 s->is_jmp = DISAS_WFI;
2603 return 0;
2604 }
Peter Maydell87f19eb2011-07-21 07:01:51 +00002605 /* Otherwise continue to handle via helper function.
Peter Maydellcc688902011-02-25 15:04:12 +00002606 * In particular, on v7 and some v6 cores this is one of
2607 * the VA-PA registers.
2608 */
Peter Maydell87f19eb2011-07-21 07:01:51 +00002609 break;
2610 case 0x0e070f3d:
2611 /* 0,c7,c13,1: prefetch-by-MVA in v6, NOP in v7 */
2612 if (arm_feature(env, ARM_FEATURE_V6)) {
2613 return IS_USER(s) ? 1 : 0;
2614 }
2615 break;
2616 case 0x0e070f95: /* 0,c7,c5,4 : ISB */
2617 case 0x0e070f9a: /* 0,c7,c10,4: DSB */
2618 case 0x0e070fba: /* 0,c7,c10,5: DMB */
2619 /* Barriers in both v6 and v7 */
2620 if (arm_feature(env, ARM_FEATURE_V6)) {
2621 return 0;
2622 }
2623 break;
2624 default:
2625 break;
2626 }
2627
2628 if (IS_USER(s) && !cp15_user_ok(env, insn)) {
2629 return 1;
Peter Maydellcc688902011-02-25 15:04:12 +00002630 }
2631
bellardb5ff1b32005-11-26 10:38:39 +00002632 rd = (insn >> 12) & 0xf;
Riku Voipio3f26c122010-01-25 15:17:32 +02002633
2634 if (cp15_tls_load_store(env, s, insn, rd))
2635 return 0;
2636
Juha Riihimäkib75263d2009-10-22 15:17:36 +03002637 tmp2 = tcg_const_i32(insn);
balrog18c9b562007-04-30 02:02:17 +00002638 if (insn & ARM_CP_RW_BIT) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00002639 tmp = tcg_temp_new_i32();
Juha Riihimäkib75263d2009-10-22 15:17:36 +03002640 gen_helper_get_cp15(tmp, cpu_env, tmp2);
bellardb5ff1b32005-11-26 10:38:39 +00002641 /* If the destination register is r15 then sets condition codes. */
2642 if (rd != 15)
pbrook8984bd22008-03-31 03:47:48 +00002643 store_reg(s, rd, tmp);
2644 else
Peter Maydell7d1b0092011-03-06 21:39:54 +00002645 tcg_temp_free_i32(tmp);
bellardb5ff1b32005-11-26 10:38:39 +00002646 } else {
pbrook8984bd22008-03-31 03:47:48 +00002647 tmp = load_reg(s, rd);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03002648 gen_helper_set_cp15(cpu_env, tmp2, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002649 tcg_temp_free_i32(tmp);
balroga90b7312007-05-01 01:28:01 +00002650 /* Normally we would always end the TB here, but Linux
2651 * arch/arm/mach-pxa/sleep.S expects two instructions following
2652 * an MMU enable to execute from cache. Imitate this behaviour. */
2653 if (!arm_feature(env, ARM_FEATURE_XSCALE) ||
2654 (insn & 0x0fff0fff) != 0x0e010f10)
2655 gen_lookup_tb(s);
bellardb5ff1b32005-11-26 10:38:39 +00002656 }
Juha Riihimäkib75263d2009-10-22 15:17:36 +03002657 tcg_temp_free_i32(tmp2);
bellardb5ff1b32005-11-26 10:38:39 +00002658 return 0;
2659}
2660
pbrook9ee6e8b2007-11-11 00:04:49 +00002661#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n))
2662#define VFP_SREG(insn, bigbit, smallbit) \
2663 ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1))
2664#define VFP_DREG(reg, insn, bigbit, smallbit) do { \
2665 if (arm_feature(env, ARM_FEATURE_VFP3)) { \
2666 reg = (((insn) >> (bigbit)) & 0x0f) \
2667 | (((insn) >> ((smallbit) - 4)) & 0x10); \
2668 } else { \
2669 if (insn & (1 << (smallbit))) \
2670 return 1; \
2671 reg = ((insn) >> (bigbit)) & 0x0f; \
2672 }} while (0)
2673
2674#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22)
2675#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22)
2676#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7)
2677#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7)
2678#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5)
2679#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5)
2680
pbrook4373f3c2008-03-31 03:47:19 +00002681/* Move between integer and VFP cores. */
2682static TCGv gen_vfp_mrs(void)
2683{
Peter Maydell7d1b0092011-03-06 21:39:54 +00002684 TCGv tmp = tcg_temp_new_i32();
pbrook4373f3c2008-03-31 03:47:19 +00002685 tcg_gen_mov_i32(tmp, cpu_F0s);
2686 return tmp;
2687}
2688
2689static void gen_vfp_msr(TCGv tmp)
2690{
2691 tcg_gen_mov_i32(cpu_F0s, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002692 tcg_temp_free_i32(tmp);
pbrook4373f3c2008-03-31 03:47:19 +00002693}
2694
pbrookad694712008-03-31 03:48:30 +00002695static void gen_neon_dup_u8(TCGv var, int shift)
2696{
Peter Maydell7d1b0092011-03-06 21:39:54 +00002697 TCGv tmp = tcg_temp_new_i32();
pbrookad694712008-03-31 03:48:30 +00002698 if (shift)
2699 tcg_gen_shri_i32(var, var, shift);
pbrook86831432008-05-11 12:22:01 +00002700 tcg_gen_ext8u_i32(var, var);
pbrookad694712008-03-31 03:48:30 +00002701 tcg_gen_shli_i32(tmp, var, 8);
2702 tcg_gen_or_i32(var, var, tmp);
2703 tcg_gen_shli_i32(tmp, var, 16);
2704 tcg_gen_or_i32(var, var, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002705 tcg_temp_free_i32(tmp);
pbrookad694712008-03-31 03:48:30 +00002706}
2707
2708static void gen_neon_dup_low16(TCGv var)
2709{
Peter Maydell7d1b0092011-03-06 21:39:54 +00002710 TCGv tmp = tcg_temp_new_i32();
pbrook86831432008-05-11 12:22:01 +00002711 tcg_gen_ext16u_i32(var, var);
pbrookad694712008-03-31 03:48:30 +00002712 tcg_gen_shli_i32(tmp, var, 16);
2713 tcg_gen_or_i32(var, var, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002714 tcg_temp_free_i32(tmp);
pbrookad694712008-03-31 03:48:30 +00002715}
2716
2717static void gen_neon_dup_high16(TCGv var)
2718{
Peter Maydell7d1b0092011-03-06 21:39:54 +00002719 TCGv tmp = tcg_temp_new_i32();
pbrookad694712008-03-31 03:48:30 +00002720 tcg_gen_andi_i32(var, var, 0xffff0000);
2721 tcg_gen_shri_i32(tmp, var, 16);
2722 tcg_gen_or_i32(var, var, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002723 tcg_temp_free_i32(tmp);
pbrookad694712008-03-31 03:48:30 +00002724}
2725
Peter Maydell8e18cde2011-03-15 16:26:51 +00002726static TCGv gen_load_and_replicate(DisasContext *s, TCGv addr, int size)
2727{
2728 /* Load a single Neon element and replicate into a 32 bit TCG reg */
2729 TCGv tmp;
2730 switch (size) {
2731 case 0:
2732 tmp = gen_ld8u(addr, IS_USER(s));
2733 gen_neon_dup_u8(tmp, 0);
2734 break;
2735 case 1:
2736 tmp = gen_ld16u(addr, IS_USER(s));
2737 gen_neon_dup_low16(tmp);
2738 break;
2739 case 2:
2740 tmp = gen_ld32(addr, IS_USER(s));
2741 break;
2742 default: /* Avoid compiler warnings. */
2743 abort();
2744 }
2745 return tmp;
2746}
2747
Stefan Weila1c72732011-04-28 17:20:38 +02002748/* Disassemble a VFP instruction. Returns nonzero if an error occurred
bellardb7bcbe92005-02-22 19:27:29 +00002749 (ie. an undefined instruction). */
2750static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
2751{
2752 uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
2753 int dp, veclen;
Filip Navara312eea92009-10-15 14:48:19 +02002754 TCGv addr;
pbrook4373f3c2008-03-31 03:47:19 +00002755 TCGv tmp;
pbrookad694712008-03-31 03:48:30 +00002756 TCGv tmp2;
bellardb7bcbe92005-02-22 19:27:29 +00002757
pbrook40f137e2006-02-20 00:33:36 +00002758 if (!arm_feature(env, ARM_FEATURE_VFP))
2759 return 1;
2760
Peter Maydell5df8bac2011-01-14 20:39:19 +01002761 if (!s->vfp_enabled) {
pbrook9ee6e8b2007-11-11 00:04:49 +00002762 /* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */
pbrook40f137e2006-02-20 00:33:36 +00002763 if ((insn & 0x0fe00fff) != 0x0ee00a10)
2764 return 1;
2765 rn = (insn >> 16) & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00002766 if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
2767 && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
pbrook40f137e2006-02-20 00:33:36 +00002768 return 1;
2769 }
bellardb7bcbe92005-02-22 19:27:29 +00002770 dp = ((insn & 0xf00) == 0xb00);
2771 switch ((insn >> 24) & 0xf) {
2772 case 0xe:
2773 if (insn & (1 << 4)) {
2774 /* single register transfer */
bellardb7bcbe92005-02-22 19:27:29 +00002775 rd = (insn >> 12) & 0xf;
2776 if (dp) {
pbrook9ee6e8b2007-11-11 00:04:49 +00002777 int size;
2778 int pass;
2779
2780 VFP_DREG_N(rn, insn);
2781 if (insn & 0xf)
bellardb7bcbe92005-02-22 19:27:29 +00002782 return 1;
pbrook9ee6e8b2007-11-11 00:04:49 +00002783 if (insn & 0x00c00060
2784 && !arm_feature(env, ARM_FEATURE_NEON))
2785 return 1;
2786
2787 pass = (insn >> 21) & 1;
2788 if (insn & (1 << 22)) {
2789 size = 0;
2790 offset = ((insn >> 5) & 3) * 8;
2791 } else if (insn & (1 << 5)) {
2792 size = 1;
2793 offset = (insn & (1 << 6)) ? 16 : 0;
2794 } else {
2795 size = 2;
2796 offset = 0;
2797 }
balrog18c9b562007-04-30 02:02:17 +00002798 if (insn & ARM_CP_RW_BIT) {
bellardb7bcbe92005-02-22 19:27:29 +00002799 /* vfp->arm */
pbrookad694712008-03-31 03:48:30 +00002800 tmp = neon_load_reg(rn, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00002801 switch (size) {
2802 case 0:
pbrook9ee6e8b2007-11-11 00:04:49 +00002803 if (offset)
pbrookad694712008-03-31 03:48:30 +00002804 tcg_gen_shri_i32(tmp, tmp, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00002805 if (insn & (1 << 23))
pbrookad694712008-03-31 03:48:30 +00002806 gen_uxtb(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002807 else
pbrookad694712008-03-31 03:48:30 +00002808 gen_sxtb(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002809 break;
2810 case 1:
pbrook9ee6e8b2007-11-11 00:04:49 +00002811 if (insn & (1 << 23)) {
2812 if (offset) {
pbrookad694712008-03-31 03:48:30 +00002813 tcg_gen_shri_i32(tmp, tmp, 16);
pbrook9ee6e8b2007-11-11 00:04:49 +00002814 } else {
pbrookad694712008-03-31 03:48:30 +00002815 gen_uxth(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002816 }
2817 } else {
2818 if (offset) {
pbrookad694712008-03-31 03:48:30 +00002819 tcg_gen_sari_i32(tmp, tmp, 16);
pbrook9ee6e8b2007-11-11 00:04:49 +00002820 } else {
pbrookad694712008-03-31 03:48:30 +00002821 gen_sxth(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002822 }
2823 }
2824 break;
2825 case 2:
pbrook9ee6e8b2007-11-11 00:04:49 +00002826 break;
2827 }
pbrookad694712008-03-31 03:48:30 +00002828 store_reg(s, rd, tmp);
bellardb7bcbe92005-02-22 19:27:29 +00002829 } else {
2830 /* arm->vfp */
pbrookad694712008-03-31 03:48:30 +00002831 tmp = load_reg(s, rd);
pbrook9ee6e8b2007-11-11 00:04:49 +00002832 if (insn & (1 << 23)) {
2833 /* VDUP */
2834 if (size == 0) {
pbrookad694712008-03-31 03:48:30 +00002835 gen_neon_dup_u8(tmp, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00002836 } else if (size == 1) {
pbrookad694712008-03-31 03:48:30 +00002837 gen_neon_dup_low16(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002838 }
pbrookcbbccff2009-03-17 12:19:58 +00002839 for (n = 0; n <= pass * 2; n++) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00002840 tmp2 = tcg_temp_new_i32();
pbrookcbbccff2009-03-17 12:19:58 +00002841 tcg_gen_mov_i32(tmp2, tmp);
2842 neon_store_reg(rn, n, tmp2);
2843 }
2844 neon_store_reg(rn, n, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002845 } else {
2846 /* VMOV */
2847 switch (size) {
2848 case 0:
pbrookad694712008-03-31 03:48:30 +00002849 tmp2 = neon_load_reg(rn, pass);
2850 gen_bfi(tmp, tmp2, tmp, offset, 0xff);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002851 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00002852 break;
2853 case 1:
pbrookad694712008-03-31 03:48:30 +00002854 tmp2 = neon_load_reg(rn, pass);
2855 gen_bfi(tmp, tmp2, tmp, offset, 0xffff);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002856 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00002857 break;
2858 case 2:
pbrook9ee6e8b2007-11-11 00:04:49 +00002859 break;
2860 }
pbrookad694712008-03-31 03:48:30 +00002861 neon_store_reg(rn, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002862 }
bellardb7bcbe92005-02-22 19:27:29 +00002863 }
pbrook9ee6e8b2007-11-11 00:04:49 +00002864 } else { /* !dp */
2865 if ((insn & 0x6f) != 0x00)
2866 return 1;
2867 rn = VFP_SREG_N(insn);
balrog18c9b562007-04-30 02:02:17 +00002868 if (insn & ARM_CP_RW_BIT) {
bellardb7bcbe92005-02-22 19:27:29 +00002869 /* vfp->arm */
2870 if (insn & (1 << 21)) {
2871 /* system register */
pbrook40f137e2006-02-20 00:33:36 +00002872 rn >>= 1;
pbrook9ee6e8b2007-11-11 00:04:49 +00002873
bellardb7bcbe92005-02-22 19:27:29 +00002874 switch (rn) {
pbrook40f137e2006-02-20 00:33:36 +00002875 case ARM_VFP_FPSID:
pbrook4373f3c2008-03-31 03:47:19 +00002876 /* VFP2 allows access to FSID from userspace.
pbrook9ee6e8b2007-11-11 00:04:49 +00002877 VFP3 restricts all id registers to privileged
2878 accesses. */
2879 if (IS_USER(s)
2880 && arm_feature(env, ARM_FEATURE_VFP3))
2881 return 1;
pbrook4373f3c2008-03-31 03:47:19 +00002882 tmp = load_cpu_field(vfp.xregs[rn]);
pbrook9ee6e8b2007-11-11 00:04:49 +00002883 break;
pbrook40f137e2006-02-20 00:33:36 +00002884 case ARM_VFP_FPEXC:
pbrook9ee6e8b2007-11-11 00:04:49 +00002885 if (IS_USER(s))
2886 return 1;
pbrook4373f3c2008-03-31 03:47:19 +00002887 tmp = load_cpu_field(vfp.xregs[rn]);
pbrook9ee6e8b2007-11-11 00:04:49 +00002888 break;
pbrook40f137e2006-02-20 00:33:36 +00002889 case ARM_VFP_FPINST:
2890 case ARM_VFP_FPINST2:
pbrook9ee6e8b2007-11-11 00:04:49 +00002891 /* Not present in VFP3. */
2892 if (IS_USER(s)
2893 || arm_feature(env, ARM_FEATURE_VFP3))
2894 return 1;
pbrook4373f3c2008-03-31 03:47:19 +00002895 tmp = load_cpu_field(vfp.xregs[rn]);
bellardb7bcbe92005-02-22 19:27:29 +00002896 break;
pbrook40f137e2006-02-20 00:33:36 +00002897 case ARM_VFP_FPSCR:
balrog601d70b2008-04-20 01:03:45 +00002898 if (rd == 15) {
pbrook4373f3c2008-03-31 03:47:19 +00002899 tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
2900 tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
2901 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00002902 tmp = tcg_temp_new_i32();
pbrook4373f3c2008-03-31 03:47:19 +00002903 gen_helper_vfp_get_fpscr(tmp, cpu_env);
2904 }
bellardb7bcbe92005-02-22 19:27:29 +00002905 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00002906 case ARM_VFP_MVFR0:
2907 case ARM_VFP_MVFR1:
2908 if (IS_USER(s)
2909 || !arm_feature(env, ARM_FEATURE_VFP3))
2910 return 1;
pbrook4373f3c2008-03-31 03:47:19 +00002911 tmp = load_cpu_field(vfp.xregs[rn]);
pbrook9ee6e8b2007-11-11 00:04:49 +00002912 break;
bellardb7bcbe92005-02-22 19:27:29 +00002913 default:
2914 return 1;
2915 }
2916 } else {
2917 gen_mov_F0_vreg(0, rn);
pbrook4373f3c2008-03-31 03:47:19 +00002918 tmp = gen_vfp_mrs();
bellardb7bcbe92005-02-22 19:27:29 +00002919 }
2920 if (rd == 15) {
bellardb5ff1b32005-11-26 10:38:39 +00002921 /* Set the 4 flag bits in the CPSR. */
pbrook4373f3c2008-03-31 03:47:19 +00002922 gen_set_nzcv(tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002923 tcg_temp_free_i32(tmp);
pbrook4373f3c2008-03-31 03:47:19 +00002924 } else {
2925 store_reg(s, rd, tmp);
2926 }
bellardb7bcbe92005-02-22 19:27:29 +00002927 } else {
2928 /* arm->vfp */
pbrook4373f3c2008-03-31 03:47:19 +00002929 tmp = load_reg(s, rd);
bellardb7bcbe92005-02-22 19:27:29 +00002930 if (insn & (1 << 21)) {
pbrook40f137e2006-02-20 00:33:36 +00002931 rn >>= 1;
bellardb7bcbe92005-02-22 19:27:29 +00002932 /* system register */
2933 switch (rn) {
pbrook40f137e2006-02-20 00:33:36 +00002934 case ARM_VFP_FPSID:
pbrook9ee6e8b2007-11-11 00:04:49 +00002935 case ARM_VFP_MVFR0:
2936 case ARM_VFP_MVFR1:
bellardb7bcbe92005-02-22 19:27:29 +00002937 /* Writes are ignored. */
2938 break;
pbrook40f137e2006-02-20 00:33:36 +00002939 case ARM_VFP_FPSCR:
pbrook4373f3c2008-03-31 03:47:19 +00002940 gen_helper_vfp_set_fpscr(cpu_env, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00002941 tcg_temp_free_i32(tmp);
bellardb5ff1b32005-11-26 10:38:39 +00002942 gen_lookup_tb(s);
bellardb7bcbe92005-02-22 19:27:29 +00002943 break;
pbrook40f137e2006-02-20 00:33:36 +00002944 case ARM_VFP_FPEXC:
pbrook9ee6e8b2007-11-11 00:04:49 +00002945 if (IS_USER(s))
2946 return 1;
Juha Riihimäki71b3c3d2009-10-26 11:46:42 +02002947 /* TODO: VFP subarchitecture support.
2948 * For now, keep the EN bit only */
2949 tcg_gen_andi_i32(tmp, tmp, 1 << 30);
pbrook4373f3c2008-03-31 03:47:19 +00002950 store_cpu_field(tmp, vfp.xregs[rn]);
pbrook40f137e2006-02-20 00:33:36 +00002951 gen_lookup_tb(s);
2952 break;
2953 case ARM_VFP_FPINST:
2954 case ARM_VFP_FPINST2:
pbrook4373f3c2008-03-31 03:47:19 +00002955 store_cpu_field(tmp, vfp.xregs[rn]);
pbrook40f137e2006-02-20 00:33:36 +00002956 break;
bellardb7bcbe92005-02-22 19:27:29 +00002957 default:
2958 return 1;
2959 }
2960 } else {
pbrook4373f3c2008-03-31 03:47:19 +00002961 gen_vfp_msr(tmp);
bellardb7bcbe92005-02-22 19:27:29 +00002962 gen_mov_vreg_F0(0, rn);
2963 }
2964 }
2965 }
2966 } else {
2967 /* data processing */
2968 /* The opcode is in bits 23, 21, 20 and 6. */
2969 op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
2970 if (dp) {
2971 if (op == 15) {
2972 /* rn is opcode */
2973 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
2974 } else {
2975 /* rn is register number */
pbrook9ee6e8b2007-11-11 00:04:49 +00002976 VFP_DREG_N(rn, insn);
bellardb7bcbe92005-02-22 19:27:29 +00002977 }
2978
Peter Maydell04595bf2010-12-07 15:37:34 +00002979 if (op == 15 && (rn == 15 || ((rn & 0x1c) == 0x18))) {
bellardb7bcbe92005-02-22 19:27:29 +00002980 /* Integer or single precision destination. */
pbrook9ee6e8b2007-11-11 00:04:49 +00002981 rd = VFP_SREG_D(insn);
bellardb7bcbe92005-02-22 19:27:29 +00002982 } else {
pbrook9ee6e8b2007-11-11 00:04:49 +00002983 VFP_DREG_D(rd, insn);
bellardb7bcbe92005-02-22 19:27:29 +00002984 }
Peter Maydell04595bf2010-12-07 15:37:34 +00002985 if (op == 15 &&
2986 (((rn & 0x1c) == 0x10) || ((rn & 0x14) == 0x14))) {
2987 /* VCVT from int is always from S reg regardless of dp bit.
2988 * VCVT with immediate frac_bits has same format as SREG_M
2989 */
2990 rm = VFP_SREG_M(insn);
bellardb7bcbe92005-02-22 19:27:29 +00002991 } else {
pbrook9ee6e8b2007-11-11 00:04:49 +00002992 VFP_DREG_M(rm, insn);
bellardb7bcbe92005-02-22 19:27:29 +00002993 }
2994 } else {
pbrook9ee6e8b2007-11-11 00:04:49 +00002995 rn = VFP_SREG_N(insn);
bellardb7bcbe92005-02-22 19:27:29 +00002996 if (op == 15 && rn == 15) {
2997 /* Double precision destination. */
pbrook9ee6e8b2007-11-11 00:04:49 +00002998 VFP_DREG_D(rd, insn);
2999 } else {
3000 rd = VFP_SREG_D(insn);
3001 }
Peter Maydell04595bf2010-12-07 15:37:34 +00003002 /* NB that we implicitly rely on the encoding for the frac_bits
3003 * in VCVT of fixed to float being the same as that of an SREG_M
3004 */
pbrook9ee6e8b2007-11-11 00:04:49 +00003005 rm = VFP_SREG_M(insn);
bellardb7bcbe92005-02-22 19:27:29 +00003006 }
3007
Peter Maydell69d1fc22011-01-14 20:39:19 +01003008 veclen = s->vec_len;
bellardb7bcbe92005-02-22 19:27:29 +00003009 if (op == 15 && rn > 3)
3010 veclen = 0;
3011
3012 /* Shut up compiler warnings. */
3013 delta_m = 0;
3014 delta_d = 0;
3015 bank_mask = 0;
ths3b46e622007-09-17 08:09:54 +00003016
bellardb7bcbe92005-02-22 19:27:29 +00003017 if (veclen > 0) {
3018 if (dp)
3019 bank_mask = 0xc;
3020 else
3021 bank_mask = 0x18;
3022
3023 /* Figure out what type of vector operation this is. */
3024 if ((rd & bank_mask) == 0) {
3025 /* scalar */
3026 veclen = 0;
3027 } else {
3028 if (dp)
Peter Maydell69d1fc22011-01-14 20:39:19 +01003029 delta_d = (s->vec_stride >> 1) + 1;
bellardb7bcbe92005-02-22 19:27:29 +00003030 else
Peter Maydell69d1fc22011-01-14 20:39:19 +01003031 delta_d = s->vec_stride + 1;
bellardb7bcbe92005-02-22 19:27:29 +00003032
3033 if ((rm & bank_mask) == 0) {
3034 /* mixed scalar/vector */
3035 delta_m = 0;
3036 } else {
3037 /* vector */
3038 delta_m = delta_d;
3039 }
3040 }
3041 }
3042
3043 /* Load the initial operands. */
3044 if (op == 15) {
3045 switch (rn) {
3046 case 16:
3047 case 17:
3048 /* Integer source */
3049 gen_mov_F0_vreg(0, rm);
3050 break;
3051 case 8:
3052 case 9:
3053 /* Compare */
3054 gen_mov_F0_vreg(dp, rd);
3055 gen_mov_F1_vreg(dp, rm);
3056 break;
3057 case 10:
3058 case 11:
3059 /* Compare with zero */
3060 gen_mov_F0_vreg(dp, rd);
3061 gen_vfp_F1_ld0(dp);
3062 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00003063 case 20:
3064 case 21:
3065 case 22:
3066 case 23:
pbrook644ad802008-12-19 13:02:08 +00003067 case 28:
3068 case 29:
3069 case 30:
3070 case 31:
pbrook9ee6e8b2007-11-11 00:04:49 +00003071 /* Source and destination the same. */
3072 gen_mov_F0_vreg(dp, rd);
3073 break;
Peter Maydell6e0c0ed2011-07-22 00:51:20 +00003074 case 4:
3075 case 5:
3076 case 6:
3077 case 7:
3078 /* VCVTB, VCVTT: only present with the halfprec extension,
3079 * UNPREDICTABLE if bit 8 is set (we choose to UNDEF)
3080 */
3081 if (dp || !arm_feature(env, ARM_FEATURE_VFP_FP16)) {
3082 return 1;
3083 }
3084 /* Otherwise fall through */
bellardb7bcbe92005-02-22 19:27:29 +00003085 default:
3086 /* One source operand. */
3087 gen_mov_F0_vreg(dp, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00003088 break;
bellardb7bcbe92005-02-22 19:27:29 +00003089 }
3090 } else {
3091 /* Two source operands. */
3092 gen_mov_F0_vreg(dp, rn);
3093 gen_mov_F1_vreg(dp, rm);
3094 }
3095
3096 for (;;) {
3097 /* Perform the calculation. */
3098 switch (op) {
Peter Maydell605a6ae2011-05-05 19:35:35 +01003099 case 0: /* VMLA: fd + (fn * fm) */
3100 /* Note that order of inputs to the add matters for NaNs */
3101 gen_vfp_F1_mul(dp);
3102 gen_mov_F0_vreg(dp, rd);
bellardb7bcbe92005-02-22 19:27:29 +00003103 gen_vfp_add(dp);
3104 break;
Peter Maydell605a6ae2011-05-05 19:35:35 +01003105 case 1: /* VMLS: fd + -(fn * fm) */
bellardb7bcbe92005-02-22 19:27:29 +00003106 gen_vfp_mul(dp);
Peter Maydell605a6ae2011-05-05 19:35:35 +01003107 gen_vfp_F1_neg(dp);
3108 gen_mov_F0_vreg(dp, rd);
bellardb7bcbe92005-02-22 19:27:29 +00003109 gen_vfp_add(dp);
3110 break;
Peter Maydell605a6ae2011-05-05 19:35:35 +01003111 case 2: /* VNMLS: -fd + (fn * fm) */
3112 /* Note that it isn't valid to replace (-A + B) with (B - A)
3113 * or similar plausible looking simplifications
3114 * because this will give wrong results for NaNs.
3115 */
3116 gen_vfp_F1_mul(dp);
3117 gen_mov_F0_vreg(dp, rd);
bellardb7bcbe92005-02-22 19:27:29 +00003118 gen_vfp_neg(dp);
Peter Maydell605a6ae2011-05-05 19:35:35 +01003119 gen_vfp_add(dp);
3120 break;
3121 case 3: /* VNMLA: -fd + -(fn * fm) */
3122 gen_vfp_mul(dp);
3123 gen_vfp_F1_neg(dp);
3124 gen_mov_F0_vreg(dp, rd);
3125 gen_vfp_neg(dp);
3126 gen_vfp_add(dp);
bellardb7bcbe92005-02-22 19:27:29 +00003127 break;
3128 case 4: /* mul: fn * fm */
3129 gen_vfp_mul(dp);
3130 break;
3131 case 5: /* nmul: -(fn * fm) */
3132 gen_vfp_mul(dp);
3133 gen_vfp_neg(dp);
3134 break;
3135 case 6: /* add: fn + fm */
3136 gen_vfp_add(dp);
3137 break;
3138 case 7: /* sub: fn - fm */
3139 gen_vfp_sub(dp);
3140 break;
3141 case 8: /* div: fn / fm */
3142 gen_vfp_div(dp);
3143 break;
Peter Maydellda97f522011-10-19 16:14:07 +00003144 case 10: /* VFNMA : fd = muladd(-fd, fn, fm) */
3145 case 11: /* VFNMS : fd = muladd(-fd, -fn, fm) */
3146 case 12: /* VFMA : fd = muladd( fd, fn, fm) */
3147 case 13: /* VFMS : fd = muladd( fd, -fn, fm) */
3148 /* These are fused multiply-add, and must be done as one
3149 * floating point operation with no rounding between the
3150 * multiplication and addition steps.
3151 * NB that doing the negations here as separate steps is
3152 * correct : an input NaN should come out with its sign bit
3153 * flipped if it is a negated-input.
3154 */
3155 if (!arm_feature(env, ARM_FEATURE_VFP4)) {
3156 return 1;
3157 }
3158 if (dp) {
3159 TCGv_ptr fpst;
3160 TCGv_i64 frd;
3161 if (op & 1) {
3162 /* VFNMS, VFMS */
3163 gen_helper_vfp_negd(cpu_F0d, cpu_F0d);
3164 }
3165 frd = tcg_temp_new_i64();
3166 tcg_gen_ld_f64(frd, cpu_env, vfp_reg_offset(dp, rd));
3167 if (op & 2) {
3168 /* VFNMA, VFNMS */
3169 gen_helper_vfp_negd(frd, frd);
3170 }
3171 fpst = get_fpstatus_ptr(0);
3172 gen_helper_vfp_muladdd(cpu_F0d, cpu_F0d,
3173 cpu_F1d, frd, fpst);
3174 tcg_temp_free_ptr(fpst);
3175 tcg_temp_free_i64(frd);
3176 } else {
3177 TCGv_ptr fpst;
3178 TCGv_i32 frd;
3179 if (op & 1) {
3180 /* VFNMS, VFMS */
3181 gen_helper_vfp_negs(cpu_F0s, cpu_F0s);
3182 }
3183 frd = tcg_temp_new_i32();
3184 tcg_gen_ld_f32(frd, cpu_env, vfp_reg_offset(dp, rd));
3185 if (op & 2) {
3186 gen_helper_vfp_negs(frd, frd);
3187 }
3188 fpst = get_fpstatus_ptr(0);
3189 gen_helper_vfp_muladds(cpu_F0s, cpu_F0s,
3190 cpu_F1s, frd, fpst);
3191 tcg_temp_free_ptr(fpst);
3192 tcg_temp_free_i32(frd);
3193 }
3194 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00003195 case 14: /* fconst */
3196 if (!arm_feature(env, ARM_FEATURE_VFP3))
3197 return 1;
3198
3199 n = (insn << 12) & 0x80000000;
3200 i = ((insn >> 12) & 0x70) | (insn & 0xf);
3201 if (dp) {
3202 if (i & 0x40)
3203 i |= 0x3f80;
3204 else
3205 i |= 0x4000;
3206 n |= i << 16;
pbrook4373f3c2008-03-31 03:47:19 +00003207 tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
pbrook9ee6e8b2007-11-11 00:04:49 +00003208 } else {
3209 if (i & 0x40)
3210 i |= 0x780;
3211 else
3212 i |= 0x800;
3213 n |= i << 19;
balrog5b340b52008-04-14 02:19:57 +00003214 tcg_gen_movi_i32(cpu_F0s, n);
pbrook9ee6e8b2007-11-11 00:04:49 +00003215 }
pbrook9ee6e8b2007-11-11 00:04:49 +00003216 break;
bellardb7bcbe92005-02-22 19:27:29 +00003217 case 15: /* extension space */
3218 switch (rn) {
3219 case 0: /* cpy */
3220 /* no-op */
3221 break;
3222 case 1: /* abs */
3223 gen_vfp_abs(dp);
3224 break;
3225 case 2: /* neg */
3226 gen_vfp_neg(dp);
3227 break;
3228 case 3: /* sqrt */
3229 gen_vfp_sqrt(dp);
3230 break;
Paul Brook60011492009-11-19 16:45:20 +00003231 case 4: /* vcvtb.f32.f16 */
Paul Brook60011492009-11-19 16:45:20 +00003232 tmp = gen_vfp_mrs();
3233 tcg_gen_ext16u_i32(tmp, tmp);
3234 gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
Peter Maydell7d1b0092011-03-06 21:39:54 +00003235 tcg_temp_free_i32(tmp);
Paul Brook60011492009-11-19 16:45:20 +00003236 break;
3237 case 5: /* vcvtt.f32.f16 */
Paul Brook60011492009-11-19 16:45:20 +00003238 tmp = gen_vfp_mrs();
3239 tcg_gen_shri_i32(tmp, tmp, 16);
3240 gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
Peter Maydell7d1b0092011-03-06 21:39:54 +00003241 tcg_temp_free_i32(tmp);
Paul Brook60011492009-11-19 16:45:20 +00003242 break;
3243 case 6: /* vcvtb.f16.f32 */
Peter Maydell7d1b0092011-03-06 21:39:54 +00003244 tmp = tcg_temp_new_i32();
Paul Brook60011492009-11-19 16:45:20 +00003245 gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
3246 gen_mov_F0_vreg(0, rd);
3247 tmp2 = gen_vfp_mrs();
3248 tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
3249 tcg_gen_or_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00003250 tcg_temp_free_i32(tmp2);
Paul Brook60011492009-11-19 16:45:20 +00003251 gen_vfp_msr(tmp);
3252 break;
3253 case 7: /* vcvtt.f16.f32 */
Peter Maydell7d1b0092011-03-06 21:39:54 +00003254 tmp = tcg_temp_new_i32();
Paul Brook60011492009-11-19 16:45:20 +00003255 gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
3256 tcg_gen_shli_i32(tmp, tmp, 16);
3257 gen_mov_F0_vreg(0, rd);
3258 tmp2 = gen_vfp_mrs();
3259 tcg_gen_ext16u_i32(tmp2, tmp2);
3260 tcg_gen_or_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00003261 tcg_temp_free_i32(tmp2);
Paul Brook60011492009-11-19 16:45:20 +00003262 gen_vfp_msr(tmp);
3263 break;
bellardb7bcbe92005-02-22 19:27:29 +00003264 case 8: /* cmp */
3265 gen_vfp_cmp(dp);
3266 break;
3267 case 9: /* cmpe */
3268 gen_vfp_cmpe(dp);
3269 break;
3270 case 10: /* cmpz */
3271 gen_vfp_cmp(dp);
3272 break;
3273 case 11: /* cmpez */
3274 gen_vfp_F1_ld0(dp);
3275 gen_vfp_cmpe(dp);
3276 break;
3277 case 15: /* single<->double conversion */
3278 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00003279 gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
bellardb7bcbe92005-02-22 19:27:29 +00003280 else
pbrook4373f3c2008-03-31 03:47:19 +00003281 gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
bellardb7bcbe92005-02-22 19:27:29 +00003282 break;
3283 case 16: /* fuito */
Peter Maydell5500b062011-05-19 14:46:19 +01003284 gen_vfp_uito(dp, 0);
bellardb7bcbe92005-02-22 19:27:29 +00003285 break;
3286 case 17: /* fsito */
Peter Maydell5500b062011-05-19 14:46:19 +01003287 gen_vfp_sito(dp, 0);
bellardb7bcbe92005-02-22 19:27:29 +00003288 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00003289 case 20: /* fshto */
3290 if (!arm_feature(env, ARM_FEATURE_VFP3))
3291 return 1;
Peter Maydell5500b062011-05-19 14:46:19 +01003292 gen_vfp_shto(dp, 16 - rm, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00003293 break;
3294 case 21: /* fslto */
3295 if (!arm_feature(env, ARM_FEATURE_VFP3))
3296 return 1;
Peter Maydell5500b062011-05-19 14:46:19 +01003297 gen_vfp_slto(dp, 32 - rm, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00003298 break;
3299 case 22: /* fuhto */
3300 if (!arm_feature(env, ARM_FEATURE_VFP3))
3301 return 1;
Peter Maydell5500b062011-05-19 14:46:19 +01003302 gen_vfp_uhto(dp, 16 - rm, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00003303 break;
3304 case 23: /* fulto */
3305 if (!arm_feature(env, ARM_FEATURE_VFP3))
3306 return 1;
Peter Maydell5500b062011-05-19 14:46:19 +01003307 gen_vfp_ulto(dp, 32 - rm, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00003308 break;
bellardb7bcbe92005-02-22 19:27:29 +00003309 case 24: /* ftoui */
Peter Maydell5500b062011-05-19 14:46:19 +01003310 gen_vfp_toui(dp, 0);
bellardb7bcbe92005-02-22 19:27:29 +00003311 break;
3312 case 25: /* ftouiz */
Peter Maydell5500b062011-05-19 14:46:19 +01003313 gen_vfp_touiz(dp, 0);
bellardb7bcbe92005-02-22 19:27:29 +00003314 break;
3315 case 26: /* ftosi */
Peter Maydell5500b062011-05-19 14:46:19 +01003316 gen_vfp_tosi(dp, 0);
bellardb7bcbe92005-02-22 19:27:29 +00003317 break;
3318 case 27: /* ftosiz */
Peter Maydell5500b062011-05-19 14:46:19 +01003319 gen_vfp_tosiz(dp, 0);
bellardb7bcbe92005-02-22 19:27:29 +00003320 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00003321 case 28: /* ftosh */
3322 if (!arm_feature(env, ARM_FEATURE_VFP3))
3323 return 1;
Peter Maydell5500b062011-05-19 14:46:19 +01003324 gen_vfp_tosh(dp, 16 - rm, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00003325 break;
3326 case 29: /* ftosl */
3327 if (!arm_feature(env, ARM_FEATURE_VFP3))
3328 return 1;
Peter Maydell5500b062011-05-19 14:46:19 +01003329 gen_vfp_tosl(dp, 32 - rm, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00003330 break;
3331 case 30: /* ftouh */
3332 if (!arm_feature(env, ARM_FEATURE_VFP3))
3333 return 1;
Peter Maydell5500b062011-05-19 14:46:19 +01003334 gen_vfp_touh(dp, 16 - rm, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00003335 break;
3336 case 31: /* ftoul */
3337 if (!arm_feature(env, ARM_FEATURE_VFP3))
3338 return 1;
Peter Maydell5500b062011-05-19 14:46:19 +01003339 gen_vfp_toul(dp, 32 - rm, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00003340 break;
bellardb7bcbe92005-02-22 19:27:29 +00003341 default: /* undefined */
bellardb7bcbe92005-02-22 19:27:29 +00003342 return 1;
3343 }
3344 break;
3345 default: /* undefined */
bellardb7bcbe92005-02-22 19:27:29 +00003346 return 1;
3347 }
3348
3349 /* Write back the result. */
3350 if (op == 15 && (rn >= 8 && rn <= 11))
3351 ; /* Comparison, do nothing. */
Peter Maydell04595bf2010-12-07 15:37:34 +00003352 else if (op == 15 && dp && ((rn & 0x1c) == 0x18))
3353 /* VCVT double to int: always integer result. */
bellardb7bcbe92005-02-22 19:27:29 +00003354 gen_mov_vreg_F0(0, rd);
3355 else if (op == 15 && rn == 15)
3356 /* conversion */
3357 gen_mov_vreg_F0(!dp, rd);
3358 else
3359 gen_mov_vreg_F0(dp, rd);
3360
3361 /* break out of the loop if we have finished */
3362 if (veclen == 0)
3363 break;
3364
3365 if (op == 15 && delta_m == 0) {
3366 /* single source one-many */
3367 while (veclen--) {
3368 rd = ((rd + delta_d) & (bank_mask - 1))
3369 | (rd & bank_mask);
3370 gen_mov_vreg_F0(dp, rd);
3371 }
3372 break;
3373 }
3374 /* Setup the next operands. */
3375 veclen--;
3376 rd = ((rd + delta_d) & (bank_mask - 1))
3377 | (rd & bank_mask);
3378
3379 if (op == 15) {
3380 /* One source operand. */
3381 rm = ((rm + delta_m) & (bank_mask - 1))
3382 | (rm & bank_mask);
3383 gen_mov_F0_vreg(dp, rm);
3384 } else {
3385 /* Two source operands. */
3386 rn = ((rn + delta_d) & (bank_mask - 1))
3387 | (rn & bank_mask);
3388 gen_mov_F0_vreg(dp, rn);
3389 if (delta_m) {
3390 rm = ((rm + delta_m) & (bank_mask - 1))
3391 | (rm & bank_mask);
3392 gen_mov_F1_vreg(dp, rm);
3393 }
3394 }
3395 }
3396 }
3397 break;
3398 case 0xc:
3399 case 0xd:
Peter Maydell8387da82011-03-01 17:35:19 +00003400 if ((insn & 0x03e00000) == 0x00400000) {
bellardb7bcbe92005-02-22 19:27:29 +00003401 /* two-register transfer */
3402 rn = (insn >> 16) & 0xf;
3403 rd = (insn >> 12) & 0xf;
3404 if (dp) {
pbrook9ee6e8b2007-11-11 00:04:49 +00003405 VFP_DREG_M(rm, insn);
3406 } else {
3407 rm = VFP_SREG_M(insn);
3408 }
bellardb7bcbe92005-02-22 19:27:29 +00003409
balrog18c9b562007-04-30 02:02:17 +00003410 if (insn & ARM_CP_RW_BIT) {
bellardb7bcbe92005-02-22 19:27:29 +00003411 /* vfp->arm */
3412 if (dp) {
pbrook4373f3c2008-03-31 03:47:19 +00003413 gen_mov_F0_vreg(0, rm * 2);
3414 tmp = gen_vfp_mrs();
3415 store_reg(s, rd, tmp);
3416 gen_mov_F0_vreg(0, rm * 2 + 1);
3417 tmp = gen_vfp_mrs();
3418 store_reg(s, rn, tmp);
bellardb7bcbe92005-02-22 19:27:29 +00003419 } else {
3420 gen_mov_F0_vreg(0, rm);
pbrook4373f3c2008-03-31 03:47:19 +00003421 tmp = gen_vfp_mrs();
Peter Maydell8387da82011-03-01 17:35:19 +00003422 store_reg(s, rd, tmp);
bellardb7bcbe92005-02-22 19:27:29 +00003423 gen_mov_F0_vreg(0, rm + 1);
pbrook4373f3c2008-03-31 03:47:19 +00003424 tmp = gen_vfp_mrs();
Peter Maydell8387da82011-03-01 17:35:19 +00003425 store_reg(s, rn, tmp);
bellardb7bcbe92005-02-22 19:27:29 +00003426 }
3427 } else {
3428 /* arm->vfp */
3429 if (dp) {
pbrook4373f3c2008-03-31 03:47:19 +00003430 tmp = load_reg(s, rd);
3431 gen_vfp_msr(tmp);
3432 gen_mov_vreg_F0(0, rm * 2);
3433 tmp = load_reg(s, rn);
3434 gen_vfp_msr(tmp);
3435 gen_mov_vreg_F0(0, rm * 2 + 1);
bellardb7bcbe92005-02-22 19:27:29 +00003436 } else {
Peter Maydell8387da82011-03-01 17:35:19 +00003437 tmp = load_reg(s, rd);
pbrook4373f3c2008-03-31 03:47:19 +00003438 gen_vfp_msr(tmp);
bellardb7bcbe92005-02-22 19:27:29 +00003439 gen_mov_vreg_F0(0, rm);
Peter Maydell8387da82011-03-01 17:35:19 +00003440 tmp = load_reg(s, rn);
pbrook4373f3c2008-03-31 03:47:19 +00003441 gen_vfp_msr(tmp);
bellardb7bcbe92005-02-22 19:27:29 +00003442 gen_mov_vreg_F0(0, rm + 1);
3443 }
3444 }
3445 } else {
3446 /* Load/store */
3447 rn = (insn >> 16) & 0xf;
3448 if (dp)
pbrook9ee6e8b2007-11-11 00:04:49 +00003449 VFP_DREG_D(rd, insn);
bellardb7bcbe92005-02-22 19:27:29 +00003450 else
pbrook9ee6e8b2007-11-11 00:04:49 +00003451 rd = VFP_SREG_D(insn);
bellardb7bcbe92005-02-22 19:27:29 +00003452 if ((insn & 0x01200000) == 0x01000000) {
3453 /* Single load/store */
3454 offset = (insn & 0xff) << 2;
3455 if ((insn & (1 << 23)) == 0)
3456 offset = -offset;
Peter Maydell934814f2011-07-22 00:51:19 +00003457 if (s->thumb && rn == 15) {
3458 /* This is actually UNPREDICTABLE */
3459 addr = tcg_temp_new_i32();
3460 tcg_gen_movi_i32(addr, s->pc & ~2);
3461 } else {
3462 addr = load_reg(s, rn);
3463 }
Filip Navara312eea92009-10-15 14:48:19 +02003464 tcg_gen_addi_i32(addr, addr, offset);
bellardb7bcbe92005-02-22 19:27:29 +00003465 if (insn & (1 << 20)) {
Filip Navara312eea92009-10-15 14:48:19 +02003466 gen_vfp_ld(s, dp, addr);
bellardb7bcbe92005-02-22 19:27:29 +00003467 gen_mov_vreg_F0(dp, rd);
3468 } else {
3469 gen_mov_F0_vreg(dp, rd);
Filip Navara312eea92009-10-15 14:48:19 +02003470 gen_vfp_st(s, dp, addr);
bellardb7bcbe92005-02-22 19:27:29 +00003471 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00003472 tcg_temp_free_i32(addr);
bellardb7bcbe92005-02-22 19:27:29 +00003473 } else {
3474 /* load/store multiple */
Peter Maydell934814f2011-07-22 00:51:19 +00003475 int w = insn & (1 << 21);
bellardb7bcbe92005-02-22 19:27:29 +00003476 if (dp)
3477 n = (insn >> 1) & 0x7f;
3478 else
3479 n = insn & 0xff;
3480
Peter Maydell934814f2011-07-22 00:51:19 +00003481 if (w && !(((insn >> 23) ^ (insn >> 24)) & 1)) {
3482 /* P == U , W == 1 => UNDEF */
3483 return 1;
3484 }
3485 if (n == 0 || (rd + n) > 32 || (dp && n > 16)) {
3486 /* UNPREDICTABLE cases for bad immediates: we choose to
3487 * UNDEF to avoid generating huge numbers of TCG ops
3488 */
3489 return 1;
3490 }
3491 if (rn == 15 && w) {
3492 /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
3493 return 1;
3494 }
3495
3496 if (s->thumb && rn == 15) {
3497 /* This is actually UNPREDICTABLE */
3498 addr = tcg_temp_new_i32();
3499 tcg_gen_movi_i32(addr, s->pc & ~2);
3500 } else {
3501 addr = load_reg(s, rn);
3502 }
bellardb7bcbe92005-02-22 19:27:29 +00003503 if (insn & (1 << 24)) /* pre-decrement */
Filip Navara312eea92009-10-15 14:48:19 +02003504 tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2));
bellardb7bcbe92005-02-22 19:27:29 +00003505
3506 if (dp)
3507 offset = 8;
3508 else
3509 offset = 4;
3510 for (i = 0; i < n; i++) {
balrog18c9b562007-04-30 02:02:17 +00003511 if (insn & ARM_CP_RW_BIT) {
bellardb7bcbe92005-02-22 19:27:29 +00003512 /* load */
Filip Navara312eea92009-10-15 14:48:19 +02003513 gen_vfp_ld(s, dp, addr);
bellardb7bcbe92005-02-22 19:27:29 +00003514 gen_mov_vreg_F0(dp, rd + i);
3515 } else {
3516 /* store */
3517 gen_mov_F0_vreg(dp, rd + i);
Filip Navara312eea92009-10-15 14:48:19 +02003518 gen_vfp_st(s, dp, addr);
bellardb7bcbe92005-02-22 19:27:29 +00003519 }
Filip Navara312eea92009-10-15 14:48:19 +02003520 tcg_gen_addi_i32(addr, addr, offset);
bellardb7bcbe92005-02-22 19:27:29 +00003521 }
Peter Maydell934814f2011-07-22 00:51:19 +00003522 if (w) {
bellardb7bcbe92005-02-22 19:27:29 +00003523 /* writeback */
3524 if (insn & (1 << 24))
3525 offset = -offset * n;
3526 else if (dp && (insn & 1))
3527 offset = 4;
3528 else
3529 offset = 0;
3530
3531 if (offset != 0)
Filip Navara312eea92009-10-15 14:48:19 +02003532 tcg_gen_addi_i32(addr, addr, offset);
3533 store_reg(s, rn, addr);
3534 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00003535 tcg_temp_free_i32(addr);
bellardb7bcbe92005-02-22 19:27:29 +00003536 }
3537 }
3538 }
3539 break;
3540 default:
3541 /* Should never happen. */
3542 return 1;
3543 }
3544 return 0;
3545}
3546
bellard6e256c92005-11-20 10:32:05 +00003547static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
bellardc53be332005-10-30 21:39:19 +00003548{
bellard6e256c92005-11-20 10:32:05 +00003549 TranslationBlock *tb;
3550
3551 tb = s->tb;
3552 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
bellard57fec1f2008-02-01 10:50:11 +00003553 tcg_gen_goto_tb(n);
pbrook8984bd22008-03-31 03:47:48 +00003554 gen_set_pc_im(dest);
Stefan Weil4b4a72e2011-04-02 13:36:31 +02003555 tcg_gen_exit_tb((tcg_target_long)tb + n);
bellard6e256c92005-11-20 10:32:05 +00003556 } else {
pbrook8984bd22008-03-31 03:47:48 +00003557 gen_set_pc_im(dest);
bellard57fec1f2008-02-01 10:50:11 +00003558 tcg_gen_exit_tb(0);
bellard6e256c92005-11-20 10:32:05 +00003559 }
bellardc53be332005-10-30 21:39:19 +00003560}
3561
bellard8aaca4c2005-04-23 18:27:52 +00003562static inline void gen_jmp (DisasContext *s, uint32_t dest)
3563{
ths551bd272008-07-03 17:57:36 +00003564 if (unlikely(s->singlestep_enabled)) {
bellard8aaca4c2005-04-23 18:27:52 +00003565 /* An indirect jump so that we still trigger the debug exception. */
bellard5899f382005-04-27 20:25:20 +00003566 if (s->thumb)
pbrookd9ba4832008-03-31 03:46:50 +00003567 dest |= 1;
3568 gen_bx_im(s, dest);
bellard8aaca4c2005-04-23 18:27:52 +00003569 } else {
bellard6e256c92005-11-20 10:32:05 +00003570 gen_goto_tb(s, 0, dest);
bellard8aaca4c2005-04-23 18:27:52 +00003571 s->is_jmp = DISAS_TB_JUMP;
3572 }
3573}
3574
pbrookd9ba4832008-03-31 03:46:50 +00003575static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y)
bellardb5ff1b32005-11-26 10:38:39 +00003576{
bellardee097182005-12-04 18:56:28 +00003577 if (x)
pbrookd9ba4832008-03-31 03:46:50 +00003578 tcg_gen_sari_i32(t0, t0, 16);
bellardb5ff1b32005-11-26 10:38:39 +00003579 else
pbrookd9ba4832008-03-31 03:46:50 +00003580 gen_sxth(t0);
bellardee097182005-12-04 18:56:28 +00003581 if (y)
pbrookd9ba4832008-03-31 03:46:50 +00003582 tcg_gen_sari_i32(t1, t1, 16);
bellardb5ff1b32005-11-26 10:38:39 +00003583 else
pbrookd9ba4832008-03-31 03:46:50 +00003584 gen_sxth(t1);
3585 tcg_gen_mul_i32(t0, t0, t1);
bellardb5ff1b32005-11-26 10:38:39 +00003586}
3587
3588/* Return the mask of PSR bits set by a MSR instruction. */
pbrook9ee6e8b2007-11-11 00:04:49 +00003589static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) {
bellardb5ff1b32005-11-26 10:38:39 +00003590 uint32_t mask;
3591
3592 mask = 0;
3593 if (flags & (1 << 0))
3594 mask |= 0xff;
3595 if (flags & (1 << 1))
3596 mask |= 0xff00;
3597 if (flags & (1 << 2))
3598 mask |= 0xff0000;
3599 if (flags & (1 << 3))
3600 mask |= 0xff000000;
pbrook9ee6e8b2007-11-11 00:04:49 +00003601
pbrook2ae23e72006-02-11 16:20:39 +00003602 /* Mask out undefined bits. */
pbrook9ee6e8b2007-11-11 00:04:49 +00003603 mask &= ~CPSR_RESERVED;
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04003604 if (!arm_feature(env, ARM_FEATURE_V4T))
3605 mask &= ~CPSR_T;
3606 if (!arm_feature(env, ARM_FEATURE_V5))
3607 mask &= ~CPSR_Q; /* V5TE in reality*/
pbrook9ee6e8b2007-11-11 00:04:49 +00003608 if (!arm_feature(env, ARM_FEATURE_V6))
pbrooke160c512007-11-11 14:36:36 +00003609 mask &= ~(CPSR_E | CPSR_GE);
pbrook9ee6e8b2007-11-11 00:04:49 +00003610 if (!arm_feature(env, ARM_FEATURE_THUMB2))
pbrooke160c512007-11-11 14:36:36 +00003611 mask &= ~CPSR_IT;
pbrook9ee6e8b2007-11-11 00:04:49 +00003612 /* Mask out execution state bits. */
pbrook2ae23e72006-02-11 16:20:39 +00003613 if (!spsr)
pbrooke160c512007-11-11 14:36:36 +00003614 mask &= ~CPSR_EXEC;
bellardb5ff1b32005-11-26 10:38:39 +00003615 /* Mask out privileged bits. */
3616 if (IS_USER(s))
pbrook9ee6e8b2007-11-11 00:04:49 +00003617 mask &= CPSR_USER;
bellardb5ff1b32005-11-26 10:38:39 +00003618 return mask;
3619}
3620
Filip Navara2fbac542009-10-15 12:43:04 +02003621/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
3622static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv t0)
bellardb5ff1b32005-11-26 10:38:39 +00003623{
pbrookd9ba4832008-03-31 03:46:50 +00003624 TCGv tmp;
bellardb5ff1b32005-11-26 10:38:39 +00003625 if (spsr) {
3626 /* ??? This is also undefined in system mode. */
3627 if (IS_USER(s))
3628 return 1;
pbrookd9ba4832008-03-31 03:46:50 +00003629
3630 tmp = load_cpu_field(spsr);
3631 tcg_gen_andi_i32(tmp, tmp, ~mask);
Filip Navara2fbac542009-10-15 12:43:04 +02003632 tcg_gen_andi_i32(t0, t0, mask);
3633 tcg_gen_or_i32(tmp, tmp, t0);
pbrookd9ba4832008-03-31 03:46:50 +00003634 store_cpu_field(tmp, spsr);
bellardb5ff1b32005-11-26 10:38:39 +00003635 } else {
Filip Navara2fbac542009-10-15 12:43:04 +02003636 gen_set_cpsr(t0, mask);
bellardb5ff1b32005-11-26 10:38:39 +00003637 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00003638 tcg_temp_free_i32(t0);
bellardb5ff1b32005-11-26 10:38:39 +00003639 gen_lookup_tb(s);
3640 return 0;
3641}
3642
Filip Navara2fbac542009-10-15 12:43:04 +02003643/* Returns nonzero if access to the PSR is not permitted. */
3644static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val)
3645{
3646 TCGv tmp;
Peter Maydell7d1b0092011-03-06 21:39:54 +00003647 tmp = tcg_temp_new_i32();
Filip Navara2fbac542009-10-15 12:43:04 +02003648 tcg_gen_movi_i32(tmp, val);
3649 return gen_set_psr(s, mask, spsr, tmp);
3650}
3651
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03003652/* Generate an old-style exception return. Marks pc as dead. */
3653static void gen_exception_return(DisasContext *s, TCGv pc)
bellardb5ff1b32005-11-26 10:38:39 +00003654{
pbrookd9ba4832008-03-31 03:46:50 +00003655 TCGv tmp;
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03003656 store_reg(s, 15, pc);
pbrookd9ba4832008-03-31 03:46:50 +00003657 tmp = load_cpu_field(spsr);
3658 gen_set_cpsr(tmp, 0xffffffff);
Peter Maydell7d1b0092011-03-06 21:39:54 +00003659 tcg_temp_free_i32(tmp);
bellardb5ff1b32005-11-26 10:38:39 +00003660 s->is_jmp = DISAS_UPDATE;
3661}
3662
pbrookb0109802008-03-31 03:47:03 +00003663/* Generate a v6 exception return. Marks both values as dead. */
3664static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr)
pbrook9ee6e8b2007-11-11 00:04:49 +00003665{
pbrookb0109802008-03-31 03:47:03 +00003666 gen_set_cpsr(cpsr, 0xffffffff);
Peter Maydell7d1b0092011-03-06 21:39:54 +00003667 tcg_temp_free_i32(cpsr);
pbrookb0109802008-03-31 03:47:03 +00003668 store_reg(s, 15, pc);
pbrook9ee6e8b2007-11-11 00:04:49 +00003669 s->is_jmp = DISAS_UPDATE;
3670}
3671
3672static inline void
3673gen_set_condexec (DisasContext *s)
3674{
3675 if (s->condexec_mask) {
pbrook8f012452008-03-31 03:46:03 +00003676 uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
Peter Maydell7d1b0092011-03-06 21:39:54 +00003677 TCGv tmp = tcg_temp_new_i32();
pbrook8f012452008-03-31 03:46:03 +00003678 tcg_gen_movi_i32(tmp, val);
pbrookd9ba4832008-03-31 03:46:50 +00003679 store_cpu_field(tmp, condexec_bits);
pbrook9ee6e8b2007-11-11 00:04:49 +00003680 }
3681}
3682
Peter Maydellbc4a0de2011-01-14 20:39:19 +01003683static void gen_exception_insn(DisasContext *s, int offset, int excp)
3684{
3685 gen_set_condexec(s);
3686 gen_set_pc_im(s->pc - offset);
3687 gen_exception(excp);
3688 s->is_jmp = DISAS_JUMP;
3689}
3690
pbrook9ee6e8b2007-11-11 00:04:49 +00003691static void gen_nop_hint(DisasContext *s, int val)
3692{
3693 switch (val) {
3694 case 3: /* wfi */
pbrook8984bd22008-03-31 03:47:48 +00003695 gen_set_pc_im(s->pc);
pbrook9ee6e8b2007-11-11 00:04:49 +00003696 s->is_jmp = DISAS_WFI;
3697 break;
3698 case 2: /* wfe */
3699 case 4: /* sev */
3700 /* TODO: Implement SEV and WFE. May help SMP performance. */
3701 default: /* nop */
3702 break;
3703 }
3704}
3705
pbrookad694712008-03-31 03:48:30 +00003706#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
pbrook9ee6e8b2007-11-11 00:04:49 +00003707
Peter Maydell62698be2011-04-11 16:26:11 +01003708static inline void gen_neon_add(int size, TCGv t0, TCGv t1)
pbrook9ee6e8b2007-11-11 00:04:49 +00003709{
3710 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02003711 case 0: gen_helper_neon_add_u8(t0, t0, t1); break;
3712 case 1: gen_helper_neon_add_u16(t0, t0, t1); break;
3713 case 2: tcg_gen_add_i32(t0, t0, t1); break;
Peter Maydell62698be2011-04-11 16:26:11 +01003714 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00003715 }
pbrook9ee6e8b2007-11-11 00:04:49 +00003716}
3717
Filip Navaradd8fbd72009-10-15 13:07:14 +02003718static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1)
pbrookad694712008-03-31 03:48:30 +00003719{
3720 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02003721 case 0: gen_helper_neon_sub_u8(t0, t1, t0); break;
3722 case 1: gen_helper_neon_sub_u16(t0, t1, t0); break;
3723 case 2: tcg_gen_sub_i32(t0, t1, t0); break;
pbrookad694712008-03-31 03:48:30 +00003724 default: return;
3725 }
3726}
3727
3728/* 32-bit pairwise ops end up the same as the elementwise versions. */
3729#define gen_helper_neon_pmax_s32 gen_helper_neon_max_s32
3730#define gen_helper_neon_pmax_u32 gen_helper_neon_max_u32
3731#define gen_helper_neon_pmin_s32 gen_helper_neon_min_s32
3732#define gen_helper_neon_pmin_u32 gen_helper_neon_min_u32
3733
pbrookad694712008-03-31 03:48:30 +00003734#define GEN_NEON_INTEGER_OP_ENV(name) do { \
3735 switch ((size << 1) | u) { \
3736 case 0: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003737 gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003738 break; \
3739 case 1: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003740 gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003741 break; \
3742 case 2: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003743 gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003744 break; \
3745 case 3: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003746 gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003747 break; \
3748 case 4: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003749 gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003750 break; \
3751 case 5: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003752 gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003753 break; \
3754 default: return 1; \
3755 }} while (0)
pbrook9ee6e8b2007-11-11 00:04:49 +00003756
3757#define GEN_NEON_INTEGER_OP(name) do { \
3758 switch ((size << 1) | u) { \
pbrookad694712008-03-31 03:48:30 +00003759 case 0: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003760 gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003761 break; \
3762 case 1: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003763 gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003764 break; \
3765 case 2: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003766 gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003767 break; \
3768 case 3: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003769 gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003770 break; \
3771 case 4: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003772 gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003773 break; \
3774 case 5: \
Filip Navaradd8fbd72009-10-15 13:07:14 +02003775 gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \
pbrookad694712008-03-31 03:48:30 +00003776 break; \
pbrook9ee6e8b2007-11-11 00:04:49 +00003777 default: return 1; \
3778 }} while (0)
3779
Filip Navaradd8fbd72009-10-15 13:07:14 +02003780static TCGv neon_load_scratch(int scratch)
pbrook9ee6e8b2007-11-11 00:04:49 +00003781{
Peter Maydell7d1b0092011-03-06 21:39:54 +00003782 TCGv tmp = tcg_temp_new_i32();
Filip Navaradd8fbd72009-10-15 13:07:14 +02003783 tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
3784 return tmp;
pbrook9ee6e8b2007-11-11 00:04:49 +00003785}
3786
Filip Navaradd8fbd72009-10-15 13:07:14 +02003787static void neon_store_scratch(int scratch, TCGv var)
pbrook9ee6e8b2007-11-11 00:04:49 +00003788{
Filip Navaradd8fbd72009-10-15 13:07:14 +02003789 tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
Peter Maydell7d1b0092011-03-06 21:39:54 +00003790 tcg_temp_free_i32(var);
pbrook9ee6e8b2007-11-11 00:04:49 +00003791}
3792
Filip Navaradd8fbd72009-10-15 13:07:14 +02003793static inline TCGv neon_get_scalar(int size, int reg)
pbrook9ee6e8b2007-11-11 00:04:49 +00003794{
Filip Navaradd8fbd72009-10-15 13:07:14 +02003795 TCGv tmp;
pbrook9ee6e8b2007-11-11 00:04:49 +00003796 if (size == 1) {
Peter Maydell0fad6ef2011-01-19 19:29:53 +00003797 tmp = neon_load_reg(reg & 7, reg >> 4);
3798 if (reg & 8) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02003799 gen_neon_dup_high16(tmp);
Peter Maydell0fad6ef2011-01-19 19:29:53 +00003800 } else {
3801 gen_neon_dup_low16(tmp);
Filip Navaradd8fbd72009-10-15 13:07:14 +02003802 }
Peter Maydell0fad6ef2011-01-19 19:29:53 +00003803 } else {
3804 tmp = neon_load_reg(reg & 15, reg >> 4);
pbrook9ee6e8b2007-11-11 00:04:49 +00003805 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02003806 return tmp;
pbrook9ee6e8b2007-11-11 00:04:49 +00003807}
3808
Peter Maydell02acedf2011-02-14 10:22:48 +00003809static int gen_neon_unzip(int rd, int rm, int size, int q)
Filip Navara19457612009-10-15 12:45:57 +02003810{
Peter Maydell02acedf2011-02-14 10:22:48 +00003811 TCGv tmp, tmp2;
Peter Maydell600b8282011-04-11 16:26:20 +01003812 if (!q && size == 2) {
Peter Maydell02acedf2011-02-14 10:22:48 +00003813 return 1;
3814 }
3815 tmp = tcg_const_i32(rd);
3816 tmp2 = tcg_const_i32(rm);
3817 if (q) {
3818 switch (size) {
3819 case 0:
Peter Maydell02da0b22011-05-25 13:31:02 +00003820 gen_helper_neon_qunzip8(cpu_env, tmp, tmp2);
Peter Maydell02acedf2011-02-14 10:22:48 +00003821 break;
3822 case 1:
Peter Maydell02da0b22011-05-25 13:31:02 +00003823 gen_helper_neon_qunzip16(cpu_env, tmp, tmp2);
Peter Maydell02acedf2011-02-14 10:22:48 +00003824 break;
3825 case 2:
Peter Maydell02da0b22011-05-25 13:31:02 +00003826 gen_helper_neon_qunzip32(cpu_env, tmp, tmp2);
Peter Maydell02acedf2011-02-14 10:22:48 +00003827 break;
3828 default:
3829 abort();
3830 }
3831 } else {
3832 switch (size) {
3833 case 0:
Peter Maydell02da0b22011-05-25 13:31:02 +00003834 gen_helper_neon_unzip8(cpu_env, tmp, tmp2);
Peter Maydell02acedf2011-02-14 10:22:48 +00003835 break;
3836 case 1:
Peter Maydell02da0b22011-05-25 13:31:02 +00003837 gen_helper_neon_unzip16(cpu_env, tmp, tmp2);
Peter Maydell02acedf2011-02-14 10:22:48 +00003838 break;
3839 default:
3840 abort();
3841 }
3842 }
3843 tcg_temp_free_i32(tmp);
3844 tcg_temp_free_i32(tmp2);
3845 return 0;
Filip Navara19457612009-10-15 12:45:57 +02003846}
3847
Peter Maydelld68a6f32011-02-14 10:22:49 +00003848static int gen_neon_zip(int rd, int rm, int size, int q)
Filip Navara19457612009-10-15 12:45:57 +02003849{
3850 TCGv tmp, tmp2;
Peter Maydell600b8282011-04-11 16:26:20 +01003851 if (!q && size == 2) {
Peter Maydelld68a6f32011-02-14 10:22:49 +00003852 return 1;
3853 }
3854 tmp = tcg_const_i32(rd);
3855 tmp2 = tcg_const_i32(rm);
3856 if (q) {
3857 switch (size) {
3858 case 0:
Peter Maydell02da0b22011-05-25 13:31:02 +00003859 gen_helper_neon_qzip8(cpu_env, tmp, tmp2);
Peter Maydelld68a6f32011-02-14 10:22:49 +00003860 break;
3861 case 1:
Peter Maydell02da0b22011-05-25 13:31:02 +00003862 gen_helper_neon_qzip16(cpu_env, tmp, tmp2);
Peter Maydelld68a6f32011-02-14 10:22:49 +00003863 break;
3864 case 2:
Peter Maydell02da0b22011-05-25 13:31:02 +00003865 gen_helper_neon_qzip32(cpu_env, tmp, tmp2);
Peter Maydelld68a6f32011-02-14 10:22:49 +00003866 break;
3867 default:
3868 abort();
3869 }
3870 } else {
3871 switch (size) {
3872 case 0:
Peter Maydell02da0b22011-05-25 13:31:02 +00003873 gen_helper_neon_zip8(cpu_env, tmp, tmp2);
Peter Maydelld68a6f32011-02-14 10:22:49 +00003874 break;
3875 case 1:
Peter Maydell02da0b22011-05-25 13:31:02 +00003876 gen_helper_neon_zip16(cpu_env, tmp, tmp2);
Peter Maydelld68a6f32011-02-14 10:22:49 +00003877 break;
3878 default:
3879 abort();
3880 }
3881 }
3882 tcg_temp_free_i32(tmp);
3883 tcg_temp_free_i32(tmp2);
3884 return 0;
Filip Navara19457612009-10-15 12:45:57 +02003885}
3886
Filip Navara19457612009-10-15 12:45:57 +02003887static void gen_neon_trn_u8(TCGv t0, TCGv t1)
3888{
3889 TCGv rd, tmp;
3890
Peter Maydell7d1b0092011-03-06 21:39:54 +00003891 rd = tcg_temp_new_i32();
3892 tmp = tcg_temp_new_i32();
Filip Navara19457612009-10-15 12:45:57 +02003893
3894 tcg_gen_shli_i32(rd, t0, 8);
3895 tcg_gen_andi_i32(rd, rd, 0xff00ff00);
3896 tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
3897 tcg_gen_or_i32(rd, rd, tmp);
3898
3899 tcg_gen_shri_i32(t1, t1, 8);
3900 tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
3901 tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
3902 tcg_gen_or_i32(t1, t1, tmp);
3903 tcg_gen_mov_i32(t0, rd);
3904
Peter Maydell7d1b0092011-03-06 21:39:54 +00003905 tcg_temp_free_i32(tmp);
3906 tcg_temp_free_i32(rd);
Filip Navara19457612009-10-15 12:45:57 +02003907}
3908
3909static void gen_neon_trn_u16(TCGv t0, TCGv t1)
3910{
3911 TCGv rd, tmp;
3912
Peter Maydell7d1b0092011-03-06 21:39:54 +00003913 rd = tcg_temp_new_i32();
3914 tmp = tcg_temp_new_i32();
Filip Navara19457612009-10-15 12:45:57 +02003915
3916 tcg_gen_shli_i32(rd, t0, 16);
3917 tcg_gen_andi_i32(tmp, t1, 0xffff);
3918 tcg_gen_or_i32(rd, rd, tmp);
3919 tcg_gen_shri_i32(t1, t1, 16);
3920 tcg_gen_andi_i32(tmp, t0, 0xffff0000);
3921 tcg_gen_or_i32(t1, t1, tmp);
3922 tcg_gen_mov_i32(t0, rd);
3923
Peter Maydell7d1b0092011-03-06 21:39:54 +00003924 tcg_temp_free_i32(tmp);
3925 tcg_temp_free_i32(rd);
Filip Navara19457612009-10-15 12:45:57 +02003926}
3927
3928
pbrook9ee6e8b2007-11-11 00:04:49 +00003929static struct {
3930 int nregs;
3931 int interleave;
3932 int spacing;
3933} neon_ls_element_type[11] = {
3934 {4, 4, 1},
3935 {4, 4, 2},
3936 {4, 1, 1},
3937 {4, 2, 1},
3938 {3, 3, 1},
3939 {3, 3, 2},
3940 {3, 1, 1},
3941 {1, 1, 1},
3942 {2, 2, 1},
3943 {2, 2, 2},
3944 {2, 1, 1}
3945};
3946
3947/* Translate a NEON load/store element instruction. Return nonzero if the
3948 instruction is invalid. */
3949static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
3950{
3951 int rd, rn, rm;
3952 int op;
3953 int nregs;
3954 int interleave;
Juha Riihimäki84496232009-10-24 15:19:01 +03003955 int spacing;
pbrook9ee6e8b2007-11-11 00:04:49 +00003956 int stride;
3957 int size;
3958 int reg;
3959 int pass;
3960 int load;
3961 int shift;
pbrook9ee6e8b2007-11-11 00:04:49 +00003962 int n;
Filip Navara1b2b1e52009-10-15 13:07:21 +02003963 TCGv addr;
pbrookb0109802008-03-31 03:47:03 +00003964 TCGv tmp;
pbrook8f8e3aa2008-03-31 03:48:01 +00003965 TCGv tmp2;
Juha Riihimäki84496232009-10-24 15:19:01 +03003966 TCGv_i64 tmp64;
pbrook9ee6e8b2007-11-11 00:04:49 +00003967
Peter Maydell5df8bac2011-01-14 20:39:19 +01003968 if (!s->vfp_enabled)
pbrook9ee6e8b2007-11-11 00:04:49 +00003969 return 1;
3970 VFP_DREG_D(rd, insn);
3971 rn = (insn >> 16) & 0xf;
3972 rm = insn & 0xf;
3973 load = (insn & (1 << 21)) != 0;
3974 if ((insn & (1 << 23)) == 0) {
3975 /* Load store all elements. */
3976 op = (insn >> 8) & 0xf;
3977 size = (insn >> 6) & 3;
Juha Riihimäki84496232009-10-24 15:19:01 +03003978 if (op > 10)
pbrook9ee6e8b2007-11-11 00:04:49 +00003979 return 1;
Peter Maydellf2dd89d2011-04-18 19:07:12 +01003980 /* Catch UNDEF cases for bad values of align field */
3981 switch (op & 0xc) {
3982 case 4:
3983 if (((insn >> 5) & 1) == 1) {
3984 return 1;
3985 }
3986 break;
3987 case 8:
3988 if (((insn >> 4) & 3) == 3) {
3989 return 1;
3990 }
3991 break;
3992 default:
3993 break;
3994 }
pbrook9ee6e8b2007-11-11 00:04:49 +00003995 nregs = neon_ls_element_type[op].nregs;
3996 interleave = neon_ls_element_type[op].interleave;
Juha Riihimäki84496232009-10-24 15:19:01 +03003997 spacing = neon_ls_element_type[op].spacing;
3998 if (size == 3 && (interleave | spacing) != 1)
3999 return 1;
Peter Maydelle318a602011-03-15 16:26:52 +00004000 addr = tcg_temp_new_i32();
Aurelien Jarnodcc65022009-10-18 16:00:18 +02004001 load_reg_var(s, addr, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00004002 stride = (1 << size) * interleave;
4003 for (reg = 0; reg < nregs; reg++) {
4004 if (interleave > 2 || (interleave == 2 && nregs == 2)) {
Aurelien Jarnodcc65022009-10-18 16:00:18 +02004005 load_reg_var(s, addr, rn);
4006 tcg_gen_addi_i32(addr, addr, (1 << size) * reg);
pbrook9ee6e8b2007-11-11 00:04:49 +00004007 } else if (interleave == 2 && nregs == 4 && reg == 2) {
Aurelien Jarnodcc65022009-10-18 16:00:18 +02004008 load_reg_var(s, addr, rn);
4009 tcg_gen_addi_i32(addr, addr, 1 << size);
pbrook9ee6e8b2007-11-11 00:04:49 +00004010 }
Juha Riihimäki84496232009-10-24 15:19:01 +03004011 if (size == 3) {
4012 if (load) {
4013 tmp64 = gen_ld64(addr, IS_USER(s));
4014 neon_store_reg64(tmp64, rd);
4015 tcg_temp_free_i64(tmp64);
4016 } else {
4017 tmp64 = tcg_temp_new_i64();
4018 neon_load_reg64(tmp64, rd);
4019 gen_st64(tmp64, addr, IS_USER(s));
4020 }
4021 tcg_gen_addi_i32(addr, addr, stride);
4022 } else {
4023 for (pass = 0; pass < 2; pass++) {
4024 if (size == 2) {
4025 if (load) {
4026 tmp = gen_ld32(addr, IS_USER(s));
4027 neon_store_reg(rd, pass, tmp);
4028 } else {
4029 tmp = neon_load_reg(rd, pass);
4030 gen_st32(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00004031 }
Juha Riihimäki84496232009-10-24 15:19:01 +03004032 tcg_gen_addi_i32(addr, addr, stride);
4033 } else if (size == 1) {
4034 if (load) {
4035 tmp = gen_ld16u(addr, IS_USER(s));
4036 tcg_gen_addi_i32(addr, addr, stride);
4037 tmp2 = gen_ld16u(addr, IS_USER(s));
4038 tcg_gen_addi_i32(addr, addr, stride);
Paul Brook41ba8342010-06-11 20:01:00 +01004039 tcg_gen_shli_i32(tmp2, tmp2, 16);
4040 tcg_gen_or_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00004041 tcg_temp_free_i32(tmp2);
Juha Riihimäki84496232009-10-24 15:19:01 +03004042 neon_store_reg(rd, pass, tmp);
4043 } else {
4044 tmp = neon_load_reg(rd, pass);
Peter Maydell7d1b0092011-03-06 21:39:54 +00004045 tmp2 = tcg_temp_new_i32();
Juha Riihimäki84496232009-10-24 15:19:01 +03004046 tcg_gen_shri_i32(tmp2, tmp, 16);
4047 gen_st16(tmp, addr, IS_USER(s));
4048 tcg_gen_addi_i32(addr, addr, stride);
4049 gen_st16(tmp2, addr, IS_USER(s));
Filip Navara1b2b1e52009-10-15 13:07:21 +02004050 tcg_gen_addi_i32(addr, addr, stride);
pbrook9ee6e8b2007-11-11 00:04:49 +00004051 }
Juha Riihimäki84496232009-10-24 15:19:01 +03004052 } else /* size == 0 */ {
4053 if (load) {
4054 TCGV_UNUSED(tmp2);
4055 for (n = 0; n < 4; n++) {
4056 tmp = gen_ld8u(addr, IS_USER(s));
4057 tcg_gen_addi_i32(addr, addr, stride);
4058 if (n == 0) {
4059 tmp2 = tmp;
4060 } else {
Paul Brook41ba8342010-06-11 20:01:00 +01004061 tcg_gen_shli_i32(tmp, tmp, n * 8);
4062 tcg_gen_or_i32(tmp2, tmp2, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00004063 tcg_temp_free_i32(tmp);
Juha Riihimäki84496232009-10-24 15:19:01 +03004064 }
4065 }
4066 neon_store_reg(rd, pass, tmp2);
4067 } else {
4068 tmp2 = neon_load_reg(rd, pass);
4069 for (n = 0; n < 4; n++) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00004070 tmp = tcg_temp_new_i32();
Juha Riihimäki84496232009-10-24 15:19:01 +03004071 if (n == 0) {
4072 tcg_gen_mov_i32(tmp, tmp2);
4073 } else {
4074 tcg_gen_shri_i32(tmp, tmp2, n * 8);
4075 }
4076 gen_st8(tmp, addr, IS_USER(s));
4077 tcg_gen_addi_i32(addr, addr, stride);
4078 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00004079 tcg_temp_free_i32(tmp2);
Juha Riihimäki84496232009-10-24 15:19:01 +03004080 }
pbrook9ee6e8b2007-11-11 00:04:49 +00004081 }
4082 }
4083 }
Juha Riihimäki84496232009-10-24 15:19:01 +03004084 rd += spacing;
pbrook9ee6e8b2007-11-11 00:04:49 +00004085 }
Peter Maydelle318a602011-03-15 16:26:52 +00004086 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00004087 stride = nregs * 8;
4088 } else {
4089 size = (insn >> 10) & 3;
4090 if (size == 3) {
4091 /* Load single element to all lanes. */
Peter Maydell8e18cde2011-03-15 16:26:51 +00004092 int a = (insn >> 4) & 1;
4093 if (!load) {
pbrook9ee6e8b2007-11-11 00:04:49 +00004094 return 1;
Peter Maydell8e18cde2011-03-15 16:26:51 +00004095 }
pbrook9ee6e8b2007-11-11 00:04:49 +00004096 size = (insn >> 6) & 3;
4097 nregs = ((insn >> 8) & 3) + 1;
Peter Maydell8e18cde2011-03-15 16:26:51 +00004098
4099 if (size == 3) {
4100 if (nregs != 4 || a == 0) {
pbrook9ee6e8b2007-11-11 00:04:49 +00004101 return 1;
4102 }
Peter Maydell8e18cde2011-03-15 16:26:51 +00004103 /* For VLD4 size==3 a == 1 means 32 bits at 16 byte alignment */
4104 size = 2;
4105 }
4106 if (nregs == 1 && a == 1 && size == 0) {
4107 return 1;
4108 }
4109 if (nregs == 3 && a == 1) {
4110 return 1;
4111 }
Peter Maydelle318a602011-03-15 16:26:52 +00004112 addr = tcg_temp_new_i32();
Peter Maydell8e18cde2011-03-15 16:26:51 +00004113 load_reg_var(s, addr, rn);
4114 if (nregs == 1) {
4115 /* VLD1 to all lanes: bit 5 indicates how many Dregs to write */
4116 tmp = gen_load_and_replicate(s, addr, size);
4117 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0));
4118 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1));
4119 if (insn & (1 << 5)) {
4120 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 0));
4121 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 1));
4122 }
4123 tcg_temp_free_i32(tmp);
4124 } else {
4125 /* VLD2/3/4 to all lanes: bit 5 indicates register stride */
4126 stride = (insn & (1 << 5)) ? 2 : 1;
4127 for (reg = 0; reg < nregs; reg++) {
4128 tmp = gen_load_and_replicate(s, addr, size);
4129 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0));
4130 tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1));
4131 tcg_temp_free_i32(tmp);
4132 tcg_gen_addi_i32(addr, addr, 1 << size);
4133 rd += stride;
4134 }
pbrook9ee6e8b2007-11-11 00:04:49 +00004135 }
Peter Maydelle318a602011-03-15 16:26:52 +00004136 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00004137 stride = (1 << size) * nregs;
4138 } else {
4139 /* Single element. */
Peter Maydell93262b12011-04-18 19:07:11 +01004140 int idx = (insn >> 4) & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00004141 pass = (insn >> 7) & 1;
4142 switch (size) {
4143 case 0:
4144 shift = ((insn >> 5) & 3) * 8;
pbrook9ee6e8b2007-11-11 00:04:49 +00004145 stride = 1;
4146 break;
4147 case 1:
4148 shift = ((insn >> 6) & 1) * 16;
pbrook9ee6e8b2007-11-11 00:04:49 +00004149 stride = (insn & (1 << 5)) ? 2 : 1;
4150 break;
4151 case 2:
4152 shift = 0;
pbrook9ee6e8b2007-11-11 00:04:49 +00004153 stride = (insn & (1 << 6)) ? 2 : 1;
4154 break;
4155 default:
4156 abort();
4157 }
4158 nregs = ((insn >> 8) & 3) + 1;
Peter Maydell93262b12011-04-18 19:07:11 +01004159 /* Catch the UNDEF cases. This is unavoidably a bit messy. */
4160 switch (nregs) {
4161 case 1:
4162 if (((idx & (1 << size)) != 0) ||
4163 (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) {
4164 return 1;
4165 }
4166 break;
4167 case 3:
4168 if ((idx & 1) != 0) {
4169 return 1;
4170 }
4171 /* fall through */
4172 case 2:
4173 if (size == 2 && (idx & 2) != 0) {
4174 return 1;
4175 }
4176 break;
4177 case 4:
4178 if ((size == 2) && ((idx & 3) == 3)) {
4179 return 1;
4180 }
4181 break;
4182 default:
4183 abort();
4184 }
4185 if ((rd + stride * (nregs - 1)) > 31) {
4186 /* Attempts to write off the end of the register file
4187 * are UNPREDICTABLE; we choose to UNDEF because otherwise
4188 * the neon_load_reg() would write off the end of the array.
4189 */
4190 return 1;
4191 }
Peter Maydelle318a602011-03-15 16:26:52 +00004192 addr = tcg_temp_new_i32();
Aurelien Jarnodcc65022009-10-18 16:00:18 +02004193 load_reg_var(s, addr, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00004194 for (reg = 0; reg < nregs; reg++) {
4195 if (load) {
pbrook9ee6e8b2007-11-11 00:04:49 +00004196 switch (size) {
4197 case 0:
Filip Navara1b2b1e52009-10-15 13:07:21 +02004198 tmp = gen_ld8u(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00004199 break;
4200 case 1:
Filip Navara1b2b1e52009-10-15 13:07:21 +02004201 tmp = gen_ld16u(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00004202 break;
4203 case 2:
Filip Navara1b2b1e52009-10-15 13:07:21 +02004204 tmp = gen_ld32(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00004205 break;
pbrooka50f5b92008-06-29 15:25:29 +00004206 default: /* Avoid compiler warnings. */
4207 abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00004208 }
4209 if (size != 2) {
pbrook8f8e3aa2008-03-31 03:48:01 +00004210 tmp2 = neon_load_reg(rd, pass);
4211 gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff);
Peter Maydell7d1b0092011-03-06 21:39:54 +00004212 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004213 }
pbrook8f8e3aa2008-03-31 03:48:01 +00004214 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00004215 } else { /* Store */
pbrook8f8e3aa2008-03-31 03:48:01 +00004216 tmp = neon_load_reg(rd, pass);
4217 if (shift)
4218 tcg_gen_shri_i32(tmp, tmp, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00004219 switch (size) {
4220 case 0:
Filip Navara1b2b1e52009-10-15 13:07:21 +02004221 gen_st8(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00004222 break;
4223 case 1:
Filip Navara1b2b1e52009-10-15 13:07:21 +02004224 gen_st16(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00004225 break;
4226 case 2:
Filip Navara1b2b1e52009-10-15 13:07:21 +02004227 gen_st32(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00004228 break;
4229 }
4230 }
4231 rd += stride;
Filip Navara1b2b1e52009-10-15 13:07:21 +02004232 tcg_gen_addi_i32(addr, addr, 1 << size);
pbrook9ee6e8b2007-11-11 00:04:49 +00004233 }
Peter Maydelle318a602011-03-15 16:26:52 +00004234 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00004235 stride = nregs * (1 << size);
4236 }
4237 }
4238 if (rm != 15) {
pbrookb26eefb2008-03-31 03:44:26 +00004239 TCGv base;
4240
4241 base = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00004242 if (rm == 13) {
pbrookb26eefb2008-03-31 03:44:26 +00004243 tcg_gen_addi_i32(base, base, stride);
pbrook9ee6e8b2007-11-11 00:04:49 +00004244 } else {
pbrookb26eefb2008-03-31 03:44:26 +00004245 TCGv index;
4246 index = load_reg(s, rm);
4247 tcg_gen_add_i32(base, base, index);
Peter Maydell7d1b0092011-03-06 21:39:54 +00004248 tcg_temp_free_i32(index);
pbrook9ee6e8b2007-11-11 00:04:49 +00004249 }
pbrookb26eefb2008-03-31 03:44:26 +00004250 store_reg(s, rn, base);
pbrook9ee6e8b2007-11-11 00:04:49 +00004251 }
4252 return 0;
4253}
4254
pbrook8f8e3aa2008-03-31 03:48:01 +00004255/* Bitwise select. dest = c ? t : f. Clobbers T and F. */
4256static void gen_neon_bsl(TCGv dest, TCGv t, TCGv f, TCGv c)
4257{
4258 tcg_gen_and_i32(t, t, c);
Aurelien Jarnof669df22009-10-15 16:45:14 +02004259 tcg_gen_andc_i32(f, f, c);
pbrook8f8e3aa2008-03-31 03:48:01 +00004260 tcg_gen_or_i32(dest, t, f);
4261}
4262
pbrooka7812ae2008-11-17 14:43:54 +00004263static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src)
pbrookad694712008-03-31 03:48:30 +00004264{
4265 switch (size) {
4266 case 0: gen_helper_neon_narrow_u8(dest, src); break;
4267 case 1: gen_helper_neon_narrow_u16(dest, src); break;
4268 case 2: tcg_gen_trunc_i64_i32(dest, src); break;
4269 default: abort();
4270 }
4271}
4272
pbrooka7812ae2008-11-17 14:43:54 +00004273static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src)
pbrookad694712008-03-31 03:48:30 +00004274{
4275 switch (size) {
Peter Maydell02da0b22011-05-25 13:31:02 +00004276 case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break;
4277 case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break;
4278 case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break;
pbrookad694712008-03-31 03:48:30 +00004279 default: abort();
4280 }
4281}
4282
pbrooka7812ae2008-11-17 14:43:54 +00004283static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src)
pbrookad694712008-03-31 03:48:30 +00004284{
4285 switch (size) {
Peter Maydell02da0b22011-05-25 13:31:02 +00004286 case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break;
4287 case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break;
4288 case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break;
pbrookad694712008-03-31 03:48:30 +00004289 default: abort();
4290 }
4291}
4292
Juha Riihimäkiaf1bbf32011-02-09 15:42:32 +00004293static inline void gen_neon_unarrow_sats(int size, TCGv dest, TCGv_i64 src)
4294{
4295 switch (size) {
Peter Maydell02da0b22011-05-25 13:31:02 +00004296 case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break;
4297 case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break;
4298 case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break;
Juha Riihimäkiaf1bbf32011-02-09 15:42:32 +00004299 default: abort();
4300 }
4301}
4302
pbrookad694712008-03-31 03:48:30 +00004303static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift,
4304 int q, int u)
4305{
4306 if (q) {
4307 if (u) {
4308 switch (size) {
4309 case 1: gen_helper_neon_rshl_u16(var, var, shift); break;
4310 case 2: gen_helper_neon_rshl_u32(var, var, shift); break;
4311 default: abort();
4312 }
4313 } else {
4314 switch (size) {
4315 case 1: gen_helper_neon_rshl_s16(var, var, shift); break;
4316 case 2: gen_helper_neon_rshl_s32(var, var, shift); break;
4317 default: abort();
4318 }
4319 }
4320 } else {
4321 if (u) {
4322 switch (size) {
Christophe Lyonb408a9b2011-02-15 13:44:46 +00004323 case 1: gen_helper_neon_shl_u16(var, var, shift); break;
4324 case 2: gen_helper_neon_shl_u32(var, var, shift); break;
pbrookad694712008-03-31 03:48:30 +00004325 default: abort();
4326 }
4327 } else {
4328 switch (size) {
4329 case 1: gen_helper_neon_shl_s16(var, var, shift); break;
4330 case 2: gen_helper_neon_shl_s32(var, var, shift); break;
4331 default: abort();
4332 }
4333 }
4334 }
4335}
4336
pbrooka7812ae2008-11-17 14:43:54 +00004337static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u)
pbrookad694712008-03-31 03:48:30 +00004338{
4339 if (u) {
4340 switch (size) {
4341 case 0: gen_helper_neon_widen_u8(dest, src); break;
4342 case 1: gen_helper_neon_widen_u16(dest, src); break;
4343 case 2: tcg_gen_extu_i32_i64(dest, src); break;
4344 default: abort();
4345 }
4346 } else {
4347 switch (size) {
4348 case 0: gen_helper_neon_widen_s8(dest, src); break;
4349 case 1: gen_helper_neon_widen_s16(dest, src); break;
4350 case 2: tcg_gen_ext_i32_i64(dest, src); break;
4351 default: abort();
4352 }
4353 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00004354 tcg_temp_free_i32(src);
pbrookad694712008-03-31 03:48:30 +00004355}
4356
4357static inline void gen_neon_addl(int size)
4358{
4359 switch (size) {
4360 case 0: gen_helper_neon_addl_u16(CPU_V001); break;
4361 case 1: gen_helper_neon_addl_u32(CPU_V001); break;
4362 case 2: tcg_gen_add_i64(CPU_V001); break;
4363 default: abort();
4364 }
4365}
4366
4367static inline void gen_neon_subl(int size)
4368{
4369 switch (size) {
4370 case 0: gen_helper_neon_subl_u16(CPU_V001); break;
4371 case 1: gen_helper_neon_subl_u32(CPU_V001); break;
4372 case 2: tcg_gen_sub_i64(CPU_V001); break;
4373 default: abort();
4374 }
4375}
4376
pbrooka7812ae2008-11-17 14:43:54 +00004377static inline void gen_neon_negl(TCGv_i64 var, int size)
pbrookad694712008-03-31 03:48:30 +00004378{
4379 switch (size) {
4380 case 0: gen_helper_neon_negl_u16(var, var); break;
4381 case 1: gen_helper_neon_negl_u32(var, var); break;
4382 case 2: gen_helper_neon_negl_u64(var, var); break;
4383 default: abort();
4384 }
4385}
4386
pbrooka7812ae2008-11-17 14:43:54 +00004387static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
pbrookad694712008-03-31 03:48:30 +00004388{
4389 switch (size) {
Peter Maydell02da0b22011-05-25 13:31:02 +00004390 case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break;
4391 case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break;
pbrookad694712008-03-31 03:48:30 +00004392 default: abort();
4393 }
4394}
4395
pbrooka7812ae2008-11-17 14:43:54 +00004396static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u)
pbrookad694712008-03-31 03:48:30 +00004397{
pbrooka7812ae2008-11-17 14:43:54 +00004398 TCGv_i64 tmp;
pbrookad694712008-03-31 03:48:30 +00004399
4400 switch ((size << 1) | u) {
4401 case 0: gen_helper_neon_mull_s8(dest, a, b); break;
4402 case 1: gen_helper_neon_mull_u8(dest, a, b); break;
4403 case 2: gen_helper_neon_mull_s16(dest, a, b); break;
4404 case 3: gen_helper_neon_mull_u16(dest, a, b); break;
4405 case 4:
4406 tmp = gen_muls_i64_i32(a, b);
4407 tcg_gen_mov_i64(dest, tmp);
Peter Maydell7d2aabe2011-03-11 13:32:34 +00004408 tcg_temp_free_i64(tmp);
pbrookad694712008-03-31 03:48:30 +00004409 break;
4410 case 5:
4411 tmp = gen_mulu_i64_i32(a, b);
4412 tcg_gen_mov_i64(dest, tmp);
Peter Maydell7d2aabe2011-03-11 13:32:34 +00004413 tcg_temp_free_i64(tmp);
pbrookad694712008-03-31 03:48:30 +00004414 break;
4415 default: abort();
4416 }
Christophe Lyonc6067f02011-01-19 15:37:58 +01004417
4418 /* gen_helper_neon_mull_[su]{8|16} do not free their parameters.
4419 Don't forget to clean them now. */
4420 if (size < 2) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00004421 tcg_temp_free_i32(a);
4422 tcg_temp_free_i32(b);
Christophe Lyonc6067f02011-01-19 15:37:58 +01004423 }
pbrookad694712008-03-31 03:48:30 +00004424}
4425
Peter Maydellc33171c2011-02-21 11:05:21 +00004426static void gen_neon_narrow_op(int op, int u, int size, TCGv dest, TCGv_i64 src)
4427{
4428 if (op) {
4429 if (u) {
4430 gen_neon_unarrow_sats(size, dest, src);
4431 } else {
4432 gen_neon_narrow(size, dest, src);
4433 }
4434 } else {
4435 if (u) {
4436 gen_neon_narrow_satu(size, dest, src);
4437 } else {
4438 gen_neon_narrow_sats(size, dest, src);
4439 }
4440 }
4441}
4442
Peter Maydell62698be2011-04-11 16:26:11 +01004443/* Symbolic constants for op fields for Neon 3-register same-length.
4444 * The values correspond to bits [11:8,4]; see the ARM ARM DDI0406B
4445 * table A7-9.
4446 */
4447#define NEON_3R_VHADD 0
4448#define NEON_3R_VQADD 1
4449#define NEON_3R_VRHADD 2
4450#define NEON_3R_LOGIC 3 /* VAND,VBIC,VORR,VMOV,VORN,VEOR,VBIF,VBIT,VBSL */
4451#define NEON_3R_VHSUB 4
4452#define NEON_3R_VQSUB 5
4453#define NEON_3R_VCGT 6
4454#define NEON_3R_VCGE 7
4455#define NEON_3R_VSHL 8
4456#define NEON_3R_VQSHL 9
4457#define NEON_3R_VRSHL 10
4458#define NEON_3R_VQRSHL 11
4459#define NEON_3R_VMAX 12
4460#define NEON_3R_VMIN 13
4461#define NEON_3R_VABD 14
4462#define NEON_3R_VABA 15
4463#define NEON_3R_VADD_VSUB 16
4464#define NEON_3R_VTST_VCEQ 17
4465#define NEON_3R_VML 18 /* VMLA, VMLAL, VMLS, VMLSL */
4466#define NEON_3R_VMUL 19
4467#define NEON_3R_VPMAX 20
4468#define NEON_3R_VPMIN 21
4469#define NEON_3R_VQDMULH_VQRDMULH 22
4470#define NEON_3R_VPADD 23
Peter Maydellda97f522011-10-19 16:14:07 +00004471#define NEON_3R_VFM 25 /* VFMA, VFMS : float fused multiply-add */
Peter Maydell62698be2011-04-11 16:26:11 +01004472#define NEON_3R_FLOAT_ARITH 26 /* float VADD, VSUB, VPADD, VABD */
4473#define NEON_3R_FLOAT_MULTIPLY 27 /* float VMLA, VMLS, VMUL */
4474#define NEON_3R_FLOAT_CMP 28 /* float VCEQ, VCGE, VCGT */
4475#define NEON_3R_FLOAT_ACMP 29 /* float VACGE, VACGT, VACLE, VACLT */
4476#define NEON_3R_FLOAT_MINMAX 30 /* float VMIN, VMAX */
4477#define NEON_3R_VRECPS_VRSQRTS 31 /* float VRECPS, VRSQRTS */
4478
4479static const uint8_t neon_3r_sizes[] = {
4480 [NEON_3R_VHADD] = 0x7,
4481 [NEON_3R_VQADD] = 0xf,
4482 [NEON_3R_VRHADD] = 0x7,
4483 [NEON_3R_LOGIC] = 0xf, /* size field encodes op type */
4484 [NEON_3R_VHSUB] = 0x7,
4485 [NEON_3R_VQSUB] = 0xf,
4486 [NEON_3R_VCGT] = 0x7,
4487 [NEON_3R_VCGE] = 0x7,
4488 [NEON_3R_VSHL] = 0xf,
4489 [NEON_3R_VQSHL] = 0xf,
4490 [NEON_3R_VRSHL] = 0xf,
4491 [NEON_3R_VQRSHL] = 0xf,
4492 [NEON_3R_VMAX] = 0x7,
4493 [NEON_3R_VMIN] = 0x7,
4494 [NEON_3R_VABD] = 0x7,
4495 [NEON_3R_VABA] = 0x7,
4496 [NEON_3R_VADD_VSUB] = 0xf,
4497 [NEON_3R_VTST_VCEQ] = 0x7,
4498 [NEON_3R_VML] = 0x7,
4499 [NEON_3R_VMUL] = 0x7,
4500 [NEON_3R_VPMAX] = 0x7,
4501 [NEON_3R_VPMIN] = 0x7,
4502 [NEON_3R_VQDMULH_VQRDMULH] = 0x6,
4503 [NEON_3R_VPADD] = 0x7,
Peter Maydellda97f522011-10-19 16:14:07 +00004504 [NEON_3R_VFM] = 0x5, /* size bit 1 encodes op */
Peter Maydell62698be2011-04-11 16:26:11 +01004505 [NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */
4506 [NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */
4507 [NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */
4508 [NEON_3R_FLOAT_ACMP] = 0x5, /* size bit 1 encodes op */
4509 [NEON_3R_FLOAT_MINMAX] = 0x5, /* size bit 1 encodes op */
4510 [NEON_3R_VRECPS_VRSQRTS] = 0x5, /* size bit 1 encodes op */
4511};
4512
Peter Maydell600b8282011-04-11 16:26:20 +01004513/* Symbolic constants for op fields for Neon 2-register miscellaneous.
4514 * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B
4515 * table A7-13.
4516 */
4517#define NEON_2RM_VREV64 0
4518#define NEON_2RM_VREV32 1
4519#define NEON_2RM_VREV16 2
4520#define NEON_2RM_VPADDL 4
4521#define NEON_2RM_VPADDL_U 5
4522#define NEON_2RM_VCLS 8
4523#define NEON_2RM_VCLZ 9
4524#define NEON_2RM_VCNT 10
4525#define NEON_2RM_VMVN 11
4526#define NEON_2RM_VPADAL 12
4527#define NEON_2RM_VPADAL_U 13
4528#define NEON_2RM_VQABS 14
4529#define NEON_2RM_VQNEG 15
4530#define NEON_2RM_VCGT0 16
4531#define NEON_2RM_VCGE0 17
4532#define NEON_2RM_VCEQ0 18
4533#define NEON_2RM_VCLE0 19
4534#define NEON_2RM_VCLT0 20
4535#define NEON_2RM_VABS 22
4536#define NEON_2RM_VNEG 23
4537#define NEON_2RM_VCGT0_F 24
4538#define NEON_2RM_VCGE0_F 25
4539#define NEON_2RM_VCEQ0_F 26
4540#define NEON_2RM_VCLE0_F 27
4541#define NEON_2RM_VCLT0_F 28
4542#define NEON_2RM_VABS_F 30
4543#define NEON_2RM_VNEG_F 31
4544#define NEON_2RM_VSWP 32
4545#define NEON_2RM_VTRN 33
4546#define NEON_2RM_VUZP 34
4547#define NEON_2RM_VZIP 35
4548#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */
4549#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */
4550#define NEON_2RM_VSHLL 38
4551#define NEON_2RM_VCVT_F16_F32 44
4552#define NEON_2RM_VCVT_F32_F16 46
4553#define NEON_2RM_VRECPE 56
4554#define NEON_2RM_VRSQRTE 57
4555#define NEON_2RM_VRECPE_F 58
4556#define NEON_2RM_VRSQRTE_F 59
4557#define NEON_2RM_VCVT_FS 60
4558#define NEON_2RM_VCVT_FU 61
4559#define NEON_2RM_VCVT_SF 62
4560#define NEON_2RM_VCVT_UF 63
4561
4562static int neon_2rm_is_float_op(int op)
4563{
4564 /* Return true if this neon 2reg-misc op is float-to-float */
4565 return (op == NEON_2RM_VABS_F || op == NEON_2RM_VNEG_F ||
4566 op >= NEON_2RM_VRECPE_F);
4567}
4568
4569/* Each entry in this array has bit n set if the insn allows
4570 * size value n (otherwise it will UNDEF). Since unallocated
4571 * op values will have no bits set they always UNDEF.
4572 */
4573static const uint8_t neon_2rm_sizes[] = {
4574 [NEON_2RM_VREV64] = 0x7,
4575 [NEON_2RM_VREV32] = 0x3,
4576 [NEON_2RM_VREV16] = 0x1,
4577 [NEON_2RM_VPADDL] = 0x7,
4578 [NEON_2RM_VPADDL_U] = 0x7,
4579 [NEON_2RM_VCLS] = 0x7,
4580 [NEON_2RM_VCLZ] = 0x7,
4581 [NEON_2RM_VCNT] = 0x1,
4582 [NEON_2RM_VMVN] = 0x1,
4583 [NEON_2RM_VPADAL] = 0x7,
4584 [NEON_2RM_VPADAL_U] = 0x7,
4585 [NEON_2RM_VQABS] = 0x7,
4586 [NEON_2RM_VQNEG] = 0x7,
4587 [NEON_2RM_VCGT0] = 0x7,
4588 [NEON_2RM_VCGE0] = 0x7,
4589 [NEON_2RM_VCEQ0] = 0x7,
4590 [NEON_2RM_VCLE0] = 0x7,
4591 [NEON_2RM_VCLT0] = 0x7,
4592 [NEON_2RM_VABS] = 0x7,
4593 [NEON_2RM_VNEG] = 0x7,
4594 [NEON_2RM_VCGT0_F] = 0x4,
4595 [NEON_2RM_VCGE0_F] = 0x4,
4596 [NEON_2RM_VCEQ0_F] = 0x4,
4597 [NEON_2RM_VCLE0_F] = 0x4,
4598 [NEON_2RM_VCLT0_F] = 0x4,
4599 [NEON_2RM_VABS_F] = 0x4,
4600 [NEON_2RM_VNEG_F] = 0x4,
4601 [NEON_2RM_VSWP] = 0x1,
4602 [NEON_2RM_VTRN] = 0x7,
4603 [NEON_2RM_VUZP] = 0x7,
4604 [NEON_2RM_VZIP] = 0x7,
4605 [NEON_2RM_VMOVN] = 0x7,
4606 [NEON_2RM_VQMOVN] = 0x7,
4607 [NEON_2RM_VSHLL] = 0x7,
4608 [NEON_2RM_VCVT_F16_F32] = 0x2,
4609 [NEON_2RM_VCVT_F32_F16] = 0x2,
4610 [NEON_2RM_VRECPE] = 0x4,
4611 [NEON_2RM_VRSQRTE] = 0x4,
4612 [NEON_2RM_VRECPE_F] = 0x4,
4613 [NEON_2RM_VRSQRTE_F] = 0x4,
4614 [NEON_2RM_VCVT_FS] = 0x4,
4615 [NEON_2RM_VCVT_FU] = 0x4,
4616 [NEON_2RM_VCVT_SF] = 0x4,
4617 [NEON_2RM_VCVT_UF] = 0x4,
4618};
4619
pbrook9ee6e8b2007-11-11 00:04:49 +00004620/* Translate a NEON data processing instruction. Return nonzero if the
4621 instruction is invalid.
pbrookad694712008-03-31 03:48:30 +00004622 We process data in a mixture of 32-bit and 64-bit chunks.
4623 Mostly we use 32-bit chunks so we can use normal scalar instructions. */
pbrook9ee6e8b2007-11-11 00:04:49 +00004624
4625static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
4626{
4627 int op;
4628 int q;
4629 int rd, rn, rm;
4630 int size;
4631 int shift;
4632 int pass;
4633 int count;
4634 int pairwise;
4635 int u;
Juha Riihimäkica9a32e2009-10-24 15:19:05 +03004636 uint32_t imm, mask;
Juha Riihimäkib75263d2009-10-22 15:17:36 +03004637 TCGv tmp, tmp2, tmp3, tmp4, tmp5;
pbrooka7812ae2008-11-17 14:43:54 +00004638 TCGv_i64 tmp64;
pbrook9ee6e8b2007-11-11 00:04:49 +00004639
Peter Maydell5df8bac2011-01-14 20:39:19 +01004640 if (!s->vfp_enabled)
pbrook9ee6e8b2007-11-11 00:04:49 +00004641 return 1;
4642 q = (insn & (1 << 6)) != 0;
4643 u = (insn >> 24) & 1;
4644 VFP_DREG_D(rd, insn);
4645 VFP_DREG_N(rn, insn);
4646 VFP_DREG_M(rm, insn);
4647 size = (insn >> 20) & 3;
4648 if ((insn & (1 << 23)) == 0) {
4649 /* Three register same length. */
4650 op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1);
Peter Maydell62698be2011-04-11 16:26:11 +01004651 /* Catch invalid op and bad size combinations: UNDEF */
4652 if ((neon_3r_sizes[op] & (1 << size)) == 0) {
4653 return 1;
4654 }
Peter Maydell25f84f72011-04-11 16:26:12 +01004655 /* All insns of this form UNDEF for either this condition or the
4656 * superset of cases "Q==1"; we catch the latter later.
4657 */
4658 if (q && ((rd | rn | rm) & 1)) {
4659 return 1;
4660 }
Peter Maydell62698be2011-04-11 16:26:11 +01004661 if (size == 3 && op != NEON_3R_LOGIC) {
4662 /* 64-bit element instructions. */
pbrook9ee6e8b2007-11-11 00:04:49 +00004663 for (pass = 0; pass < (q ? 2 : 1); pass++) {
pbrookad694712008-03-31 03:48:30 +00004664 neon_load_reg64(cpu_V0, rn + pass);
4665 neon_load_reg64(cpu_V1, rm + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004666 switch (op) {
Peter Maydell62698be2011-04-11 16:26:11 +01004667 case NEON_3R_VQADD:
pbrook9ee6e8b2007-11-11 00:04:49 +00004668 if (u) {
Peter Maydell02da0b22011-05-25 13:31:02 +00004669 gen_helper_neon_qadd_u64(cpu_V0, cpu_env,
4670 cpu_V0, cpu_V1);
pbrook9ee6e8b2007-11-11 00:04:49 +00004671 } else {
Peter Maydell02da0b22011-05-25 13:31:02 +00004672 gen_helper_neon_qadd_s64(cpu_V0, cpu_env,
4673 cpu_V0, cpu_V1);
pbrook9ee6e8b2007-11-11 00:04:49 +00004674 }
4675 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004676 case NEON_3R_VQSUB:
pbrook9ee6e8b2007-11-11 00:04:49 +00004677 if (u) {
Peter Maydell02da0b22011-05-25 13:31:02 +00004678 gen_helper_neon_qsub_u64(cpu_V0, cpu_env,
4679 cpu_V0, cpu_V1);
pbrook9ee6e8b2007-11-11 00:04:49 +00004680 } else {
Peter Maydell02da0b22011-05-25 13:31:02 +00004681 gen_helper_neon_qsub_s64(cpu_V0, cpu_env,
4682 cpu_V0, cpu_V1);
pbrookad694712008-03-31 03:48:30 +00004683 }
4684 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004685 case NEON_3R_VSHL:
pbrookad694712008-03-31 03:48:30 +00004686 if (u) {
4687 gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0);
4688 } else {
4689 gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0);
4690 }
4691 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004692 case NEON_3R_VQSHL:
pbrookad694712008-03-31 03:48:30 +00004693 if (u) {
Peter Maydell02da0b22011-05-25 13:31:02 +00004694 gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
4695 cpu_V1, cpu_V0);
pbrookad694712008-03-31 03:48:30 +00004696 } else {
Peter Maydell02da0b22011-05-25 13:31:02 +00004697 gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
4698 cpu_V1, cpu_V0);
pbrookad694712008-03-31 03:48:30 +00004699 }
4700 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004701 case NEON_3R_VRSHL:
pbrookad694712008-03-31 03:48:30 +00004702 if (u) {
4703 gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
4704 } else {
4705 gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
4706 }
4707 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004708 case NEON_3R_VQRSHL:
pbrookad694712008-03-31 03:48:30 +00004709 if (u) {
Peter Maydell02da0b22011-05-25 13:31:02 +00004710 gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
4711 cpu_V1, cpu_V0);
pbrookad694712008-03-31 03:48:30 +00004712 } else {
Peter Maydell02da0b22011-05-25 13:31:02 +00004713 gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
4714 cpu_V1, cpu_V0);
pbrook9ee6e8b2007-11-11 00:04:49 +00004715 }
4716 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004717 case NEON_3R_VADD_VSUB:
pbrook9ee6e8b2007-11-11 00:04:49 +00004718 if (u) {
pbrookad694712008-03-31 03:48:30 +00004719 tcg_gen_sub_i64(CPU_V001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004720 } else {
pbrookad694712008-03-31 03:48:30 +00004721 tcg_gen_add_i64(CPU_V001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004722 }
4723 break;
4724 default:
4725 abort();
4726 }
pbrookad694712008-03-31 03:48:30 +00004727 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004728 }
4729 return 0;
4730 }
Peter Maydell25f84f72011-04-11 16:26:12 +01004731 pairwise = 0;
pbrook9ee6e8b2007-11-11 00:04:49 +00004732 switch (op) {
Peter Maydell62698be2011-04-11 16:26:11 +01004733 case NEON_3R_VSHL:
4734 case NEON_3R_VQSHL:
4735 case NEON_3R_VRSHL:
4736 case NEON_3R_VQRSHL:
pbrook9ee6e8b2007-11-11 00:04:49 +00004737 {
pbrookad694712008-03-31 03:48:30 +00004738 int rtmp;
4739 /* Shift instruction operands are reversed. */
4740 rtmp = rn;
pbrook9ee6e8b2007-11-11 00:04:49 +00004741 rn = rm;
pbrookad694712008-03-31 03:48:30 +00004742 rm = rtmp;
pbrook9ee6e8b2007-11-11 00:04:49 +00004743 }
4744 break;
Peter Maydell25f84f72011-04-11 16:26:12 +01004745 case NEON_3R_VPADD:
4746 if (u) {
4747 return 1;
4748 }
4749 /* Fall through */
Peter Maydell62698be2011-04-11 16:26:11 +01004750 case NEON_3R_VPMAX:
4751 case NEON_3R_VPMIN:
pbrook9ee6e8b2007-11-11 00:04:49 +00004752 pairwise = 1;
4753 break;
Peter Maydell25f84f72011-04-11 16:26:12 +01004754 case NEON_3R_FLOAT_ARITH:
4755 pairwise = (u && size < 2); /* if VPADD (float) */
pbrook9ee6e8b2007-11-11 00:04:49 +00004756 break;
Peter Maydell25f84f72011-04-11 16:26:12 +01004757 case NEON_3R_FLOAT_MINMAX:
4758 pairwise = u; /* if VPMIN/VPMAX (float) */
4759 break;
4760 case NEON_3R_FLOAT_CMP:
4761 if (!u && size) {
4762 /* no encoding for U=0 C=1x */
4763 return 1;
4764 }
4765 break;
4766 case NEON_3R_FLOAT_ACMP:
4767 if (!u) {
4768 return 1;
4769 }
4770 break;
4771 case NEON_3R_VRECPS_VRSQRTS:
4772 if (u) {
4773 return 1;
4774 }
4775 break;
4776 case NEON_3R_VMUL:
4777 if (u && (size != 0)) {
4778 /* UNDEF on invalid size for polynomial subcase */
4779 return 1;
4780 }
pbrook9ee6e8b2007-11-11 00:04:49 +00004781 break;
Peter Maydellda97f522011-10-19 16:14:07 +00004782 case NEON_3R_VFM:
4783 if (!arm_feature(env, ARM_FEATURE_VFP4) || u) {
4784 return 1;
4785 }
4786 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004787 default:
pbrook9ee6e8b2007-11-11 00:04:49 +00004788 break;
4789 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02004790
Peter Maydell25f84f72011-04-11 16:26:12 +01004791 if (pairwise && q) {
4792 /* All the pairwise insns UNDEF if Q is set */
4793 return 1;
4794 }
4795
pbrook9ee6e8b2007-11-11 00:04:49 +00004796 for (pass = 0; pass < (q ? 4 : 2); pass++) {
4797
4798 if (pairwise) {
4799 /* Pairwise. */
Juha Riihimäkia5a14942011-04-11 16:26:13 +01004800 if (pass < 1) {
4801 tmp = neon_load_reg(rn, 0);
4802 tmp2 = neon_load_reg(rn, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00004803 } else {
Juha Riihimäkia5a14942011-04-11 16:26:13 +01004804 tmp = neon_load_reg(rm, 0);
4805 tmp2 = neon_load_reg(rm, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00004806 }
4807 } else {
4808 /* Elementwise. */
Filip Navaradd8fbd72009-10-15 13:07:14 +02004809 tmp = neon_load_reg(rn, pass);
4810 tmp2 = neon_load_reg(rm, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004811 }
4812 switch (op) {
Peter Maydell62698be2011-04-11 16:26:11 +01004813 case NEON_3R_VHADD:
pbrook9ee6e8b2007-11-11 00:04:49 +00004814 GEN_NEON_INTEGER_OP(hadd);
4815 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004816 case NEON_3R_VQADD:
Peter Maydell02da0b22011-05-25 13:31:02 +00004817 GEN_NEON_INTEGER_OP_ENV(qadd);
pbrook9ee6e8b2007-11-11 00:04:49 +00004818 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004819 case NEON_3R_VRHADD:
pbrook9ee6e8b2007-11-11 00:04:49 +00004820 GEN_NEON_INTEGER_OP(rhadd);
4821 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004822 case NEON_3R_LOGIC: /* Logic ops. */
pbrook9ee6e8b2007-11-11 00:04:49 +00004823 switch ((u << 2) | size) {
4824 case 0: /* VAND */
Filip Navaradd8fbd72009-10-15 13:07:14 +02004825 tcg_gen_and_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004826 break;
4827 case 1: /* BIC */
Aurelien Jarnof669df22009-10-15 16:45:14 +02004828 tcg_gen_andc_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004829 break;
4830 case 2: /* VORR */
Filip Navaradd8fbd72009-10-15 13:07:14 +02004831 tcg_gen_or_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004832 break;
4833 case 3: /* VORN */
Aurelien Jarnof669df22009-10-15 16:45:14 +02004834 tcg_gen_orc_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004835 break;
4836 case 4: /* VEOR */
Filip Navaradd8fbd72009-10-15 13:07:14 +02004837 tcg_gen_xor_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004838 break;
4839 case 5: /* VBSL */
Filip Navaradd8fbd72009-10-15 13:07:14 +02004840 tmp3 = neon_load_reg(rd, pass);
4841 gen_neon_bsl(tmp, tmp, tmp2, tmp3);
Peter Maydell7d1b0092011-03-06 21:39:54 +00004842 tcg_temp_free_i32(tmp3);
pbrook9ee6e8b2007-11-11 00:04:49 +00004843 break;
4844 case 6: /* VBIT */
Filip Navaradd8fbd72009-10-15 13:07:14 +02004845 tmp3 = neon_load_reg(rd, pass);
4846 gen_neon_bsl(tmp, tmp, tmp3, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00004847 tcg_temp_free_i32(tmp3);
pbrook9ee6e8b2007-11-11 00:04:49 +00004848 break;
4849 case 7: /* VBIF */
Filip Navaradd8fbd72009-10-15 13:07:14 +02004850 tmp3 = neon_load_reg(rd, pass);
4851 gen_neon_bsl(tmp, tmp3, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00004852 tcg_temp_free_i32(tmp3);
pbrook9ee6e8b2007-11-11 00:04:49 +00004853 break;
4854 }
4855 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004856 case NEON_3R_VHSUB:
pbrook9ee6e8b2007-11-11 00:04:49 +00004857 GEN_NEON_INTEGER_OP(hsub);
4858 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004859 case NEON_3R_VQSUB:
Peter Maydell02da0b22011-05-25 13:31:02 +00004860 GEN_NEON_INTEGER_OP_ENV(qsub);
pbrook9ee6e8b2007-11-11 00:04:49 +00004861 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004862 case NEON_3R_VCGT:
pbrook9ee6e8b2007-11-11 00:04:49 +00004863 GEN_NEON_INTEGER_OP(cgt);
4864 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004865 case NEON_3R_VCGE:
pbrook9ee6e8b2007-11-11 00:04:49 +00004866 GEN_NEON_INTEGER_OP(cge);
4867 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004868 case NEON_3R_VSHL:
pbrookad694712008-03-31 03:48:30 +00004869 GEN_NEON_INTEGER_OP(shl);
pbrook9ee6e8b2007-11-11 00:04:49 +00004870 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004871 case NEON_3R_VQSHL:
Peter Maydell02da0b22011-05-25 13:31:02 +00004872 GEN_NEON_INTEGER_OP_ENV(qshl);
pbrook9ee6e8b2007-11-11 00:04:49 +00004873 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004874 case NEON_3R_VRSHL:
pbrookad694712008-03-31 03:48:30 +00004875 GEN_NEON_INTEGER_OP(rshl);
pbrook9ee6e8b2007-11-11 00:04:49 +00004876 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004877 case NEON_3R_VQRSHL:
Peter Maydell02da0b22011-05-25 13:31:02 +00004878 GEN_NEON_INTEGER_OP_ENV(qrshl);
pbrook9ee6e8b2007-11-11 00:04:49 +00004879 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004880 case NEON_3R_VMAX:
pbrook9ee6e8b2007-11-11 00:04:49 +00004881 GEN_NEON_INTEGER_OP(max);
4882 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004883 case NEON_3R_VMIN:
pbrook9ee6e8b2007-11-11 00:04:49 +00004884 GEN_NEON_INTEGER_OP(min);
4885 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004886 case NEON_3R_VABD:
pbrook9ee6e8b2007-11-11 00:04:49 +00004887 GEN_NEON_INTEGER_OP(abd);
4888 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004889 case NEON_3R_VABA:
pbrook9ee6e8b2007-11-11 00:04:49 +00004890 GEN_NEON_INTEGER_OP(abd);
Peter Maydell7d1b0092011-03-06 21:39:54 +00004891 tcg_temp_free_i32(tmp2);
Filip Navaradd8fbd72009-10-15 13:07:14 +02004892 tmp2 = neon_load_reg(rd, pass);
4893 gen_neon_add(size, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004894 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004895 case NEON_3R_VADD_VSUB:
pbrook9ee6e8b2007-11-11 00:04:49 +00004896 if (!u) { /* VADD */
Peter Maydell62698be2011-04-11 16:26:11 +01004897 gen_neon_add(size, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004898 } else { /* VSUB */
4899 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02004900 case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break;
4901 case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break;
4902 case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break;
Peter Maydell62698be2011-04-11 16:26:11 +01004903 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00004904 }
4905 }
4906 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004907 case NEON_3R_VTST_VCEQ:
pbrook9ee6e8b2007-11-11 00:04:49 +00004908 if (!u) { /* VTST */
4909 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02004910 case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break;
4911 case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break;
4912 case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break;
Peter Maydell62698be2011-04-11 16:26:11 +01004913 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00004914 }
4915 } else { /* VCEQ */
4916 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02004917 case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
4918 case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
4919 case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
Peter Maydell62698be2011-04-11 16:26:11 +01004920 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00004921 }
4922 }
4923 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004924 case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */
pbrook9ee6e8b2007-11-11 00:04:49 +00004925 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02004926 case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
4927 case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
4928 case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
Peter Maydell62698be2011-04-11 16:26:11 +01004929 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00004930 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00004931 tcg_temp_free_i32(tmp2);
Filip Navaradd8fbd72009-10-15 13:07:14 +02004932 tmp2 = neon_load_reg(rd, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004933 if (u) { /* VMLS */
Filip Navaradd8fbd72009-10-15 13:07:14 +02004934 gen_neon_rsb(size, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004935 } else { /* VMLA */
Filip Navaradd8fbd72009-10-15 13:07:14 +02004936 gen_neon_add(size, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004937 }
4938 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004939 case NEON_3R_VMUL:
pbrook9ee6e8b2007-11-11 00:04:49 +00004940 if (u) { /* polynomial */
Filip Navaradd8fbd72009-10-15 13:07:14 +02004941 gen_helper_neon_mul_p8(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004942 } else { /* Integer */
4943 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02004944 case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
4945 case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
4946 case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
Peter Maydell62698be2011-04-11 16:26:11 +01004947 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00004948 }
4949 }
4950 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004951 case NEON_3R_VPMAX:
pbrook9ee6e8b2007-11-11 00:04:49 +00004952 GEN_NEON_INTEGER_OP(pmax);
4953 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004954 case NEON_3R_VPMIN:
pbrook9ee6e8b2007-11-11 00:04:49 +00004955 GEN_NEON_INTEGER_OP(pmin);
4956 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004957 case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high. */
pbrook9ee6e8b2007-11-11 00:04:49 +00004958 if (!u) { /* VQDMULH */
4959 switch (size) {
Peter Maydell02da0b22011-05-25 13:31:02 +00004960 case 1:
4961 gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
4962 break;
4963 case 2:
4964 gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
4965 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004966 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00004967 }
Peter Maydell62698be2011-04-11 16:26:11 +01004968 } else { /* VQRDMULH */
pbrook9ee6e8b2007-11-11 00:04:49 +00004969 switch (size) {
Peter Maydell02da0b22011-05-25 13:31:02 +00004970 case 1:
4971 gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
4972 break;
4973 case 2:
4974 gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
4975 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004976 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00004977 }
4978 }
4979 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004980 case NEON_3R_VPADD:
pbrook9ee6e8b2007-11-11 00:04:49 +00004981 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02004982 case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break;
4983 case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break;
4984 case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break;
Peter Maydell62698be2011-04-11 16:26:11 +01004985 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00004986 }
4987 break;
Peter Maydell62698be2011-04-11 16:26:11 +01004988 case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */
Peter Maydellaa47cfd2011-05-25 13:49:19 +00004989 {
4990 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
pbrook9ee6e8b2007-11-11 00:04:49 +00004991 switch ((u << 2) | size) {
4992 case 0: /* VADD */
Peter Maydellaa47cfd2011-05-25 13:49:19 +00004993 case 4: /* VPADD */
4994 gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00004995 break;
4996 case 2: /* VSUB */
Peter Maydellaa47cfd2011-05-25 13:49:19 +00004997 gen_helper_vfp_subs(tmp, tmp, tmp2, fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00004998 break;
4999 case 6: /* VABD */
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005000 gen_helper_neon_abd_f32(tmp, tmp, tmp2, fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005001 break;
5002 default:
Peter Maydell62698be2011-04-11 16:26:11 +01005003 abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00005004 }
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005005 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005006 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005007 }
Peter Maydell62698be2011-04-11 16:26:11 +01005008 case NEON_3R_FLOAT_MULTIPLY:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005009 {
5010 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
5011 gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005012 if (!u) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00005013 tcg_temp_free_i32(tmp2);
Filip Navaradd8fbd72009-10-15 13:07:14 +02005014 tmp2 = neon_load_reg(rd, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005015 if (size == 0) {
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005016 gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005017 } else {
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005018 gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005019 }
5020 }
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005021 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005022 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005023 }
Peter Maydell62698be2011-04-11 16:26:11 +01005024 case NEON_3R_FLOAT_CMP:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005025 {
5026 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005027 if (!u) {
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005028 gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005029 } else {
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005030 if (size == 0) {
5031 gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
5032 } else {
5033 gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
5034 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005035 }
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005036 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005037 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005038 }
Peter Maydell62698be2011-04-11 16:26:11 +01005039 case NEON_3R_FLOAT_ACMP:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005040 {
5041 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
5042 if (size == 0) {
5043 gen_helper_neon_acge_f32(tmp, tmp, tmp2, fpstatus);
5044 } else {
5045 gen_helper_neon_acgt_f32(tmp, tmp, tmp2, fpstatus);
5046 }
5047 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005048 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005049 }
Peter Maydell62698be2011-04-11 16:26:11 +01005050 case NEON_3R_FLOAT_MINMAX:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005051 {
5052 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
5053 if (size == 0) {
5054 gen_helper_neon_max_f32(tmp, tmp, tmp2, fpstatus);
5055 } else {
5056 gen_helper_neon_min_f32(tmp, tmp, tmp2, fpstatus);
5057 }
5058 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005059 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005060 }
Peter Maydell62698be2011-04-11 16:26:11 +01005061 case NEON_3R_VRECPS_VRSQRTS:
pbrook9ee6e8b2007-11-11 00:04:49 +00005062 if (size == 0)
Filip Navaradd8fbd72009-10-15 13:07:14 +02005063 gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00005064 else
Filip Navaradd8fbd72009-10-15 13:07:14 +02005065 gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00005066 break;
Peter Maydellda97f522011-10-19 16:14:07 +00005067 case NEON_3R_VFM:
5068 {
5069 /* VFMA, VFMS: fused multiply-add */
5070 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
5071 TCGv_i32 tmp3 = neon_load_reg(rd, pass);
5072 if (size) {
5073 /* VFMS */
5074 gen_helper_vfp_negs(tmp, tmp);
5075 }
5076 gen_helper_vfp_muladds(tmp, tmp, tmp2, tmp3, fpstatus);
5077 tcg_temp_free_i32(tmp3);
5078 tcg_temp_free_ptr(fpstatus);
5079 break;
5080 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005081 default:
5082 abort();
5083 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00005084 tcg_temp_free_i32(tmp2);
Filip Navaradd8fbd72009-10-15 13:07:14 +02005085
pbrook9ee6e8b2007-11-11 00:04:49 +00005086 /* Save the result. For elementwise operations we can put it
5087 straight into the destination register. For pairwise operations
5088 we have to be careful to avoid clobbering the source operands. */
5089 if (pairwise && rd == rm) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005090 neon_store_scratch(pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005091 } else {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005092 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005093 }
5094
5095 } /* for pass */
5096 if (pairwise && rd == rm) {
5097 for (pass = 0; pass < (q ? 4 : 2); pass++) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005098 tmp = neon_load_scratch(pass);
5099 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005100 }
5101 }
pbrookad694712008-03-31 03:48:30 +00005102 /* End of 3 register same size operations. */
pbrook9ee6e8b2007-11-11 00:04:49 +00005103 } else if (insn & (1 << 4)) {
5104 if ((insn & 0x00380080) != 0) {
5105 /* Two registers and shift. */
5106 op = (insn >> 8) & 0xf;
5107 if (insn & (1 << 7)) {
Peter Maydellcc131152011-04-11 16:26:14 +01005108 /* 64-bit shift. */
5109 if (op > 7) {
5110 return 1;
5111 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005112 size = 3;
5113 } else {
5114 size = 2;
5115 while ((insn & (1 << (size + 19))) == 0)
5116 size--;
5117 }
5118 shift = (insn >> 16) & ((1 << (3 + size)) - 1);
5119 /* To avoid excessive dumplication of ops we implement shift
5120 by immediate using the variable shift operations. */
5121 if (op < 8) {
5122 /* Shift by immediate:
5123 VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */
Peter Maydellcc131152011-04-11 16:26:14 +01005124 if (q && ((rd | rm) & 1)) {
5125 return 1;
5126 }
5127 if (!u && (op == 4 || op == 6)) {
5128 return 1;
5129 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005130 /* Right shifts are encoded as N - shift, where N is the
5131 element size in bits. */
5132 if (op <= 4)
5133 shift = shift - (1 << (size + 3));
pbrook9ee6e8b2007-11-11 00:04:49 +00005134 if (size == 3) {
5135 count = q + 1;
5136 } else {
5137 count = q ? 4: 2;
5138 }
5139 switch (size) {
5140 case 0:
5141 imm = (uint8_t) shift;
5142 imm |= imm << 8;
5143 imm |= imm << 16;
5144 break;
5145 case 1:
5146 imm = (uint16_t) shift;
5147 imm |= imm << 16;
5148 break;
5149 case 2:
5150 case 3:
5151 imm = shift;
5152 break;
5153 default:
5154 abort();
5155 }
5156
5157 for (pass = 0; pass < count; pass++) {
pbrookad694712008-03-31 03:48:30 +00005158 if (size == 3) {
5159 neon_load_reg64(cpu_V0, rm + pass);
5160 tcg_gen_movi_i64(cpu_V1, imm);
5161 switch (op) {
5162 case 0: /* VSHR */
5163 case 1: /* VSRA */
5164 if (u)
5165 gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
5166 else
5167 gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
5168 break;
5169 case 2: /* VRSHR */
5170 case 3: /* VRSRA */
5171 if (u)
5172 gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
5173 else
5174 gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
5175 break;
5176 case 4: /* VSRI */
pbrookad694712008-03-31 03:48:30 +00005177 case 5: /* VSHL, VSLI */
5178 gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
5179 break;
Peter Maydell0322b262011-01-08 16:01:16 +00005180 case 6: /* VQSHLU */
Peter Maydell02da0b22011-05-25 13:31:02 +00005181 gen_helper_neon_qshlu_s64(cpu_V0, cpu_env,
5182 cpu_V0, cpu_V1);
pbrookad694712008-03-31 03:48:30 +00005183 break;
Peter Maydell0322b262011-01-08 16:01:16 +00005184 case 7: /* VQSHL */
5185 if (u) {
Peter Maydell02da0b22011-05-25 13:31:02 +00005186 gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
Peter Maydell0322b262011-01-08 16:01:16 +00005187 cpu_V0, cpu_V1);
5188 } else {
Peter Maydell02da0b22011-05-25 13:31:02 +00005189 gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
Peter Maydell0322b262011-01-08 16:01:16 +00005190 cpu_V0, cpu_V1);
5191 }
pbrookad694712008-03-31 03:48:30 +00005192 break;
5193 }
5194 if (op == 1 || op == 3) {
5195 /* Accumulate. */
Christophe Lyon5371cb82011-01-25 18:18:08 +01005196 neon_load_reg64(cpu_V1, rd + pass);
pbrookad694712008-03-31 03:48:30 +00005197 tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
5198 } else if (op == 4 || (op == 5 && u)) {
5199 /* Insert */
Christophe Lyon923e6502011-02-08 18:39:02 +01005200 neon_load_reg64(cpu_V1, rd + pass);
5201 uint64_t mask;
5202 if (shift < -63 || shift > 63) {
5203 mask = 0;
5204 } else {
5205 if (op == 4) {
5206 mask = 0xffffffffffffffffull >> -shift;
5207 } else {
5208 mask = 0xffffffffffffffffull << shift;
5209 }
5210 }
5211 tcg_gen_andi_i64(cpu_V1, cpu_V1, ~mask);
5212 tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
pbrookad694712008-03-31 03:48:30 +00005213 }
5214 neon_store_reg64(cpu_V0, rd + pass);
5215 } else { /* size < 3 */
pbrook9ee6e8b2007-11-11 00:04:49 +00005216 /* Operands in T0 and T1. */
Filip Navaradd8fbd72009-10-15 13:07:14 +02005217 tmp = neon_load_reg(rm, pass);
Peter Maydell7d1b0092011-03-06 21:39:54 +00005218 tmp2 = tcg_temp_new_i32();
Filip Navaradd8fbd72009-10-15 13:07:14 +02005219 tcg_gen_movi_i32(tmp2, imm);
pbrookad694712008-03-31 03:48:30 +00005220 switch (op) {
5221 case 0: /* VSHR */
5222 case 1: /* VSRA */
5223 GEN_NEON_INTEGER_OP(shl);
5224 break;
5225 case 2: /* VRSHR */
5226 case 3: /* VRSRA */
5227 GEN_NEON_INTEGER_OP(rshl);
5228 break;
5229 case 4: /* VSRI */
pbrookad694712008-03-31 03:48:30 +00005230 case 5: /* VSHL, VSLI */
5231 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005232 case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break;
5233 case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break;
5234 case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break;
Peter Maydellcc131152011-04-11 16:26:14 +01005235 default: abort();
pbrookad694712008-03-31 03:48:30 +00005236 }
5237 break;
Peter Maydell0322b262011-01-08 16:01:16 +00005238 case 6: /* VQSHLU */
Peter Maydell0322b262011-01-08 16:01:16 +00005239 switch (size) {
5240 case 0:
Peter Maydell02da0b22011-05-25 13:31:02 +00005241 gen_helper_neon_qshlu_s8(tmp, cpu_env,
5242 tmp, tmp2);
Peter Maydell0322b262011-01-08 16:01:16 +00005243 break;
5244 case 1:
Peter Maydell02da0b22011-05-25 13:31:02 +00005245 gen_helper_neon_qshlu_s16(tmp, cpu_env,
5246 tmp, tmp2);
Peter Maydell0322b262011-01-08 16:01:16 +00005247 break;
5248 case 2:
Peter Maydell02da0b22011-05-25 13:31:02 +00005249 gen_helper_neon_qshlu_s32(tmp, cpu_env,
5250 tmp, tmp2);
Peter Maydell0322b262011-01-08 16:01:16 +00005251 break;
5252 default:
Peter Maydellcc131152011-04-11 16:26:14 +01005253 abort();
Peter Maydell0322b262011-01-08 16:01:16 +00005254 }
5255 break;
5256 case 7: /* VQSHL */
Peter Maydell02da0b22011-05-25 13:31:02 +00005257 GEN_NEON_INTEGER_OP_ENV(qshl);
pbrookad694712008-03-31 03:48:30 +00005258 break;
5259 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00005260 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005261
pbrookad694712008-03-31 03:48:30 +00005262 if (op == 1 || op == 3) {
5263 /* Accumulate. */
Filip Navaradd8fbd72009-10-15 13:07:14 +02005264 tmp2 = neon_load_reg(rd, pass);
Christophe Lyon5371cb82011-01-25 18:18:08 +01005265 gen_neon_add(size, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00005266 tcg_temp_free_i32(tmp2);
pbrookad694712008-03-31 03:48:30 +00005267 } else if (op == 4 || (op == 5 && u)) {
5268 /* Insert */
5269 switch (size) {
5270 case 0:
5271 if (op == 4)
Juha Riihimäkica9a32e2009-10-24 15:19:05 +03005272 mask = 0xff >> -shift;
pbrookad694712008-03-31 03:48:30 +00005273 else
Juha Riihimäkica9a32e2009-10-24 15:19:05 +03005274 mask = (uint8_t)(0xff << shift);
5275 mask |= mask << 8;
5276 mask |= mask << 16;
pbrookad694712008-03-31 03:48:30 +00005277 break;
5278 case 1:
5279 if (op == 4)
Juha Riihimäkica9a32e2009-10-24 15:19:05 +03005280 mask = 0xffff >> -shift;
pbrookad694712008-03-31 03:48:30 +00005281 else
Juha Riihimäkica9a32e2009-10-24 15:19:05 +03005282 mask = (uint16_t)(0xffff << shift);
5283 mask |= mask << 16;
pbrookad694712008-03-31 03:48:30 +00005284 break;
5285 case 2:
Juha Riihimäkica9a32e2009-10-24 15:19:05 +03005286 if (shift < -31 || shift > 31) {
5287 mask = 0;
5288 } else {
5289 if (op == 4)
5290 mask = 0xffffffffu >> -shift;
5291 else
5292 mask = 0xffffffffu << shift;
5293 }
pbrookad694712008-03-31 03:48:30 +00005294 break;
5295 default:
5296 abort();
5297 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02005298 tmp2 = neon_load_reg(rd, pass);
Juha Riihimäkica9a32e2009-10-24 15:19:05 +03005299 tcg_gen_andi_i32(tmp, tmp, mask);
5300 tcg_gen_andi_i32(tmp2, tmp2, ~mask);
Filip Navaradd8fbd72009-10-15 13:07:14 +02005301 tcg_gen_or_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00005302 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005303 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02005304 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005305 }
5306 } /* for pass */
5307 } else if (op < 10) {
pbrookad694712008-03-31 03:48:30 +00005308 /* Shift by immediate and narrow:
pbrook9ee6e8b2007-11-11 00:04:49 +00005309 VSHRN, VRSHRN, VQSHRN, VQRSHRN. */
Christophe Lyon0b36f4c2011-02-15 13:44:47 +00005310 int input_unsigned = (op == 8) ? !u : u;
Peter Maydellcc131152011-04-11 16:26:14 +01005311 if (rm & 1) {
5312 return 1;
5313 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005314 shift = shift - (1 << (size + 3));
5315 size++;
Peter Maydell92cdfae2011-02-21 11:05:22 +00005316 if (size == 3) {
pbrooka7812ae2008-11-17 14:43:54 +00005317 tmp64 = tcg_const_i64(shift);
Peter Maydell92cdfae2011-02-21 11:05:22 +00005318 neon_load_reg64(cpu_V0, rm);
5319 neon_load_reg64(cpu_V1, rm + 1);
5320 for (pass = 0; pass < 2; pass++) {
5321 TCGv_i64 in;
5322 if (pass == 0) {
5323 in = cpu_V0;
5324 } else {
5325 in = cpu_V1;
5326 }
pbrookad694712008-03-31 03:48:30 +00005327 if (q) {
Christophe Lyon0b36f4c2011-02-15 13:44:47 +00005328 if (input_unsigned) {
Peter Maydell92cdfae2011-02-21 11:05:22 +00005329 gen_helper_neon_rshl_u64(cpu_V0, in, tmp64);
Christophe Lyon0b36f4c2011-02-15 13:44:47 +00005330 } else {
Peter Maydell92cdfae2011-02-21 11:05:22 +00005331 gen_helper_neon_rshl_s64(cpu_V0, in, tmp64);
Christophe Lyon0b36f4c2011-02-15 13:44:47 +00005332 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005333 } else {
Christophe Lyon0b36f4c2011-02-15 13:44:47 +00005334 if (input_unsigned) {
Peter Maydell92cdfae2011-02-21 11:05:22 +00005335 gen_helper_neon_shl_u64(cpu_V0, in, tmp64);
Christophe Lyon0b36f4c2011-02-15 13:44:47 +00005336 } else {
Peter Maydell92cdfae2011-02-21 11:05:22 +00005337 gen_helper_neon_shl_s64(cpu_V0, in, tmp64);
Christophe Lyon0b36f4c2011-02-15 13:44:47 +00005338 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005339 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00005340 tmp = tcg_temp_new_i32();
Peter Maydell92cdfae2011-02-21 11:05:22 +00005341 gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
5342 neon_store_reg(rd, pass, tmp);
5343 } /* for pass */
5344 tcg_temp_free_i64(tmp64);
5345 } else {
5346 if (size == 1) {
5347 imm = (uint16_t)shift;
5348 imm |= imm << 16;
pbrookad694712008-03-31 03:48:30 +00005349 } else {
Peter Maydell92cdfae2011-02-21 11:05:22 +00005350 /* size == 2 */
5351 imm = (uint32_t)shift;
5352 }
5353 tmp2 = tcg_const_i32(imm);
5354 tmp4 = neon_load_reg(rm + 1, 0);
5355 tmp5 = neon_load_reg(rm + 1, 1);
5356 for (pass = 0; pass < 2; pass++) {
5357 if (pass == 0) {
5358 tmp = neon_load_reg(rm, 0);
5359 } else {
5360 tmp = tmp4;
5361 }
Christophe Lyon0b36f4c2011-02-15 13:44:47 +00005362 gen_neon_shift_narrow(size, tmp, tmp2, q,
5363 input_unsigned);
Peter Maydell92cdfae2011-02-21 11:05:22 +00005364 if (pass == 0) {
5365 tmp3 = neon_load_reg(rm, 1);
5366 } else {
5367 tmp3 = tmp5;
5368 }
Christophe Lyon0b36f4c2011-02-15 13:44:47 +00005369 gen_neon_shift_narrow(size, tmp3, tmp2, q,
5370 input_unsigned);
pbrook36aa55d2008-09-21 13:48:32 +00005371 tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
Peter Maydell7d1b0092011-03-06 21:39:54 +00005372 tcg_temp_free_i32(tmp);
5373 tcg_temp_free_i32(tmp3);
5374 tmp = tcg_temp_new_i32();
Peter Maydell92cdfae2011-02-21 11:05:22 +00005375 gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
5376 neon_store_reg(rd, pass, tmp);
5377 } /* for pass */
Christophe Lyonc6067f02011-01-19 15:37:58 +01005378 tcg_temp_free_i32(tmp2);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03005379 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005380 } else if (op == 10) {
Peter Maydellcc131152011-04-11 16:26:14 +01005381 /* VSHLL, VMOVL */
5382 if (q || (rd & 1)) {
pbrook9ee6e8b2007-11-11 00:04:49 +00005383 return 1;
Peter Maydellcc131152011-04-11 16:26:14 +01005384 }
pbrookad694712008-03-31 03:48:30 +00005385 tmp = neon_load_reg(rm, 0);
5386 tmp2 = neon_load_reg(rm, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005387 for (pass = 0; pass < 2; pass++) {
pbrookad694712008-03-31 03:48:30 +00005388 if (pass == 1)
5389 tmp = tmp2;
pbrook9ee6e8b2007-11-11 00:04:49 +00005390
pbrookad694712008-03-31 03:48:30 +00005391 gen_neon_widen(cpu_V0, tmp, size, u);
5392
pbrook9ee6e8b2007-11-11 00:04:49 +00005393 if (shift != 0) {
5394 /* The shift is less than the width of the source
pbrookad694712008-03-31 03:48:30 +00005395 type, so we can just shift the whole register. */
5396 tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
Christophe Lyonacdf01e2011-02-09 13:19:15 +01005397 /* Widen the result of shift: we need to clear
5398 * the potential overflow bits resulting from
5399 * left bits of the narrow input appearing as
5400 * right bits of left the neighbour narrow
5401 * input. */
pbrookad694712008-03-31 03:48:30 +00005402 if (size < 2 || !u) {
5403 uint64_t imm64;
5404 if (size == 0) {
5405 imm = (0xffu >> (8 - shift));
5406 imm |= imm << 16;
Christophe Lyonacdf01e2011-02-09 13:19:15 +01005407 } else if (size == 1) {
pbrookad694712008-03-31 03:48:30 +00005408 imm = 0xffff >> (16 - shift);
Christophe Lyonacdf01e2011-02-09 13:19:15 +01005409 } else {
5410 /* size == 2 */
5411 imm = 0xffffffff >> (32 - shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00005412 }
Christophe Lyonacdf01e2011-02-09 13:19:15 +01005413 if (size < 2) {
5414 imm64 = imm | (((uint64_t)imm) << 32);
5415 } else {
5416 imm64 = imm;
5417 }
5418 tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);
pbrook9ee6e8b2007-11-11 00:04:49 +00005419 }
5420 }
pbrookad694712008-03-31 03:48:30 +00005421 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005422 }
Peter Maydellf73534a2010-12-07 15:37:34 +00005423 } else if (op >= 14) {
pbrook9ee6e8b2007-11-11 00:04:49 +00005424 /* VCVT fixed-point. */
Peter Maydellcc131152011-04-11 16:26:14 +01005425 if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
5426 return 1;
5427 }
Peter Maydellf73534a2010-12-07 15:37:34 +00005428 /* We have already masked out the must-be-1 top bit of imm6,
5429 * hence this 32-shift where the ARM ARM has 64-imm6.
5430 */
5431 shift = 32 - shift;
pbrook9ee6e8b2007-11-11 00:04:49 +00005432 for (pass = 0; pass < (q ? 4 : 2); pass++) {
pbrook4373f3c2008-03-31 03:47:19 +00005433 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
Peter Maydellf73534a2010-12-07 15:37:34 +00005434 if (!(op & 1)) {
pbrook9ee6e8b2007-11-11 00:04:49 +00005435 if (u)
Peter Maydell5500b062011-05-19 14:46:19 +01005436 gen_vfp_ulto(0, shift, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005437 else
Peter Maydell5500b062011-05-19 14:46:19 +01005438 gen_vfp_slto(0, shift, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005439 } else {
5440 if (u)
Peter Maydell5500b062011-05-19 14:46:19 +01005441 gen_vfp_toul(0, shift, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005442 else
Peter Maydell5500b062011-05-19 14:46:19 +01005443 gen_vfp_tosl(0, shift, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005444 }
pbrook4373f3c2008-03-31 03:47:19 +00005445 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
pbrook9ee6e8b2007-11-11 00:04:49 +00005446 }
5447 } else {
5448 return 1;
5449 }
5450 } else { /* (insn & 0x00380080) == 0 */
5451 int invert;
Peter Maydell7d80fee2011-04-11 16:26:16 +01005452 if (q && (rd & 1)) {
5453 return 1;
5454 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005455
5456 op = (insn >> 8) & 0xf;
5457 /* One register and immediate. */
5458 imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
5459 invert = (insn & (1 << 5)) != 0;
Peter Maydell7d80fee2011-04-11 16:26:16 +01005460 /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
5461 * We choose to not special-case this and will behave as if a
5462 * valid constant encoding of 0 had been given.
5463 */
pbrook9ee6e8b2007-11-11 00:04:49 +00005464 switch (op) {
5465 case 0: case 1:
5466 /* no-op */
5467 break;
5468 case 2: case 3:
5469 imm <<= 8;
5470 break;
5471 case 4: case 5:
5472 imm <<= 16;
5473 break;
5474 case 6: case 7:
5475 imm <<= 24;
5476 break;
5477 case 8: case 9:
5478 imm |= imm << 16;
5479 break;
5480 case 10: case 11:
5481 imm = (imm << 8) | (imm << 24);
5482 break;
5483 case 12:
Juha Riihimäki8e312092010-03-26 16:06:55 +00005484 imm = (imm << 8) | 0xff;
pbrook9ee6e8b2007-11-11 00:04:49 +00005485 break;
5486 case 13:
5487 imm = (imm << 16) | 0xffff;
5488 break;
5489 case 14:
5490 imm |= (imm << 8) | (imm << 16) | (imm << 24);
5491 if (invert)
5492 imm = ~imm;
5493 break;
5494 case 15:
Peter Maydell7d80fee2011-04-11 16:26:16 +01005495 if (invert) {
5496 return 1;
5497 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005498 imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
5499 | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
5500 break;
5501 }
5502 if (invert)
5503 imm = ~imm;
5504
pbrook9ee6e8b2007-11-11 00:04:49 +00005505 for (pass = 0; pass < (q ? 4 : 2); pass++) {
5506 if (op & 1 && op < 12) {
pbrookad694712008-03-31 03:48:30 +00005507 tmp = neon_load_reg(rd, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005508 if (invert) {
5509 /* The immediate value has already been inverted, so
5510 BIC becomes AND. */
pbrookad694712008-03-31 03:48:30 +00005511 tcg_gen_andi_i32(tmp, tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00005512 } else {
pbrookad694712008-03-31 03:48:30 +00005513 tcg_gen_ori_i32(tmp, tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00005514 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005515 } else {
pbrookad694712008-03-31 03:48:30 +00005516 /* VMOV, VMVN. */
Peter Maydell7d1b0092011-03-06 21:39:54 +00005517 tmp = tcg_temp_new_i32();
pbrook9ee6e8b2007-11-11 00:04:49 +00005518 if (op == 14 && invert) {
Juha Riihimäkia5a14942011-04-11 16:26:13 +01005519 int n;
pbrookad694712008-03-31 03:48:30 +00005520 uint32_t val;
5521 val = 0;
pbrook9ee6e8b2007-11-11 00:04:49 +00005522 for (n = 0; n < 4; n++) {
5523 if (imm & (1 << (n + (pass & 1) * 4)))
pbrookad694712008-03-31 03:48:30 +00005524 val |= 0xff << (n * 8);
pbrook9ee6e8b2007-11-11 00:04:49 +00005525 }
pbrookad694712008-03-31 03:48:30 +00005526 tcg_gen_movi_i32(tmp, val);
5527 } else {
5528 tcg_gen_movi_i32(tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00005529 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005530 }
pbrookad694712008-03-31 03:48:30 +00005531 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005532 }
5533 }
pbrooke4b38612008-09-21 23:15:38 +00005534 } else { /* (insn & 0x00800010 == 0x00800000) */
pbrook9ee6e8b2007-11-11 00:04:49 +00005535 if (size != 3) {
5536 op = (insn >> 8) & 0xf;
5537 if ((insn & (1 << 6)) == 0) {
5538 /* Three registers of different lengths. */
5539 int src1_wide;
5540 int src2_wide;
5541 int prewiden;
Peter Maydell695272d2011-04-11 16:26:17 +01005542 /* undefreq: bit 0 : UNDEF if size != 0
5543 * bit 1 : UNDEF if size == 0
5544 * bit 2 : UNDEF if U == 1
5545 * Note that [1:0] set implies 'always UNDEF'
5546 */
5547 int undefreq;
5548 /* prewiden, src1_wide, src2_wide, undefreq */
5549 static const int neon_3reg_wide[16][4] = {
5550 {1, 0, 0, 0}, /* VADDL */
5551 {1, 1, 0, 0}, /* VADDW */
5552 {1, 0, 0, 0}, /* VSUBL */
5553 {1, 1, 0, 0}, /* VSUBW */
5554 {0, 1, 1, 0}, /* VADDHN */
5555 {0, 0, 0, 0}, /* VABAL */
5556 {0, 1, 1, 0}, /* VSUBHN */
5557 {0, 0, 0, 0}, /* VABDL */
5558 {0, 0, 0, 0}, /* VMLAL */
5559 {0, 0, 0, 6}, /* VQDMLAL */
5560 {0, 0, 0, 0}, /* VMLSL */
5561 {0, 0, 0, 6}, /* VQDMLSL */
5562 {0, 0, 0, 0}, /* Integer VMULL */
5563 {0, 0, 0, 2}, /* VQDMULL */
5564 {0, 0, 0, 5}, /* Polynomial VMULL */
5565 {0, 0, 0, 3}, /* Reserved: always UNDEF */
pbrook9ee6e8b2007-11-11 00:04:49 +00005566 };
5567
5568 prewiden = neon_3reg_wide[op][0];
5569 src1_wide = neon_3reg_wide[op][1];
5570 src2_wide = neon_3reg_wide[op][2];
Peter Maydell695272d2011-04-11 16:26:17 +01005571 undefreq = neon_3reg_wide[op][3];
pbrook9ee6e8b2007-11-11 00:04:49 +00005572
Peter Maydell695272d2011-04-11 16:26:17 +01005573 if (((undefreq & 1) && (size != 0)) ||
5574 ((undefreq & 2) && (size == 0)) ||
5575 ((undefreq & 4) && u)) {
pbrookad694712008-03-31 03:48:30 +00005576 return 1;
Peter Maydell695272d2011-04-11 16:26:17 +01005577 }
5578 if ((src1_wide && (rn & 1)) ||
5579 (src2_wide && (rm & 1)) ||
5580 (!src2_wide && (rd & 1))) {
5581 return 1;
5582 }
pbrookad694712008-03-31 03:48:30 +00005583
pbrook9ee6e8b2007-11-11 00:04:49 +00005584 /* Avoid overlapping operands. Wide source operands are
5585 always aligned so will never overlap with wide
5586 destinations in problematic ways. */
pbrook8f8e3aa2008-03-31 03:48:01 +00005587 if (rd == rm && !src2_wide) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005588 tmp = neon_load_reg(rm, 1);
5589 neon_store_scratch(2, tmp);
pbrook8f8e3aa2008-03-31 03:48:01 +00005590 } else if (rd == rn && !src1_wide) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005591 tmp = neon_load_reg(rn, 1);
5592 neon_store_scratch(2, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005593 }
pbrooka50f5b92008-06-29 15:25:29 +00005594 TCGV_UNUSED(tmp3);
pbrook9ee6e8b2007-11-11 00:04:49 +00005595 for (pass = 0; pass < 2; pass++) {
pbrook8f8e3aa2008-03-31 03:48:01 +00005596 if (src1_wide) {
pbrookad694712008-03-31 03:48:30 +00005597 neon_load_reg64(cpu_V0, rn + pass);
pbrooka50f5b92008-06-29 15:25:29 +00005598 TCGV_UNUSED(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005599 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +00005600 if (pass == 1 && rd == rn) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005601 tmp = neon_load_scratch(2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005602 } else {
pbrookad694712008-03-31 03:48:30 +00005603 tmp = neon_load_reg(rn, pass);
5604 }
5605 if (prewiden) {
5606 gen_neon_widen(cpu_V0, tmp, size, u);
pbrook9ee6e8b2007-11-11 00:04:49 +00005607 }
5608 }
pbrookad694712008-03-31 03:48:30 +00005609 if (src2_wide) {
5610 neon_load_reg64(cpu_V1, rm + pass);
pbrooka50f5b92008-06-29 15:25:29 +00005611 TCGV_UNUSED(tmp2);
pbrookad694712008-03-31 03:48:30 +00005612 } else {
5613 if (pass == 1 && rd == rm) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005614 tmp2 = neon_load_scratch(2);
pbrookad694712008-03-31 03:48:30 +00005615 } else {
5616 tmp2 = neon_load_reg(rm, pass);
5617 }
5618 if (prewiden) {
5619 gen_neon_widen(cpu_V1, tmp2, size, u);
5620 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005621 }
5622 switch (op) {
5623 case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
pbrookad694712008-03-31 03:48:30 +00005624 gen_neon_addl(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005625 break;
Riku Voipio79b0e532010-02-05 15:52:28 +00005626 case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHN, VRSUBHN */
pbrookad694712008-03-31 03:48:30 +00005627 gen_neon_subl(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005628 break;
5629 case 5: case 7: /* VABAL, VABDL */
5630 switch ((size << 1) | u) {
pbrookad694712008-03-31 03:48:30 +00005631 case 0:
5632 gen_helper_neon_abdl_s16(cpu_V0, tmp, tmp2);
5633 break;
5634 case 1:
5635 gen_helper_neon_abdl_u16(cpu_V0, tmp, tmp2);
5636 break;
5637 case 2:
5638 gen_helper_neon_abdl_s32(cpu_V0, tmp, tmp2);
5639 break;
5640 case 3:
5641 gen_helper_neon_abdl_u32(cpu_V0, tmp, tmp2);
5642 break;
5643 case 4:
5644 gen_helper_neon_abdl_s64(cpu_V0, tmp, tmp2);
5645 break;
5646 case 5:
5647 gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2);
5648 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005649 default: abort();
5650 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00005651 tcg_temp_free_i32(tmp2);
5652 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005653 break;
5654 case 8: case 9: case 10: case 11: case 12: case 13:
5655 /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
pbrookad694712008-03-31 03:48:30 +00005656 gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
pbrook9ee6e8b2007-11-11 00:04:49 +00005657 break;
5658 case 14: /* Polynomial VMULL */
Peter Maydelle5ca24c2011-02-10 19:07:55 +00005659 gen_helper_neon_mull_p8(cpu_V0, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00005660 tcg_temp_free_i32(tmp2);
5661 tcg_temp_free_i32(tmp);
Peter Maydelle5ca24c2011-02-10 19:07:55 +00005662 break;
Peter Maydell695272d2011-04-11 16:26:17 +01005663 default: /* 15 is RESERVED: caught earlier */
5664 abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00005665 }
Peter Maydellebcd88c2011-02-11 12:26:47 +00005666 if (op == 13) {
5667 /* VQDMULL */
5668 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
5669 neon_store_reg64(cpu_V0, rd + pass);
5670 } else if (op == 5 || (op >= 8 && op <= 11)) {
pbrook9ee6e8b2007-11-11 00:04:49 +00005671 /* Accumulate. */
Peter Maydellebcd88c2011-02-11 12:26:47 +00005672 neon_load_reg64(cpu_V1, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005673 switch (op) {
Peter Maydell4dc064e2011-02-11 12:26:48 +00005674 case 10: /* VMLSL */
5675 gen_neon_negl(cpu_V0, size);
5676 /* Fall through */
5677 case 5: case 8: /* VABAL, VMLAL */
pbrookad694712008-03-31 03:48:30 +00005678 gen_neon_addl(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005679 break;
5680 case 9: case 11: /* VQDMLAL, VQDMLSL */
pbrookad694712008-03-31 03:48:30 +00005681 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
Peter Maydell4dc064e2011-02-11 12:26:48 +00005682 if (op == 11) {
5683 gen_neon_negl(cpu_V0, size);
5684 }
pbrookad694712008-03-31 03:48:30 +00005685 gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
5686 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005687 default:
5688 abort();
5689 }
pbrookad694712008-03-31 03:48:30 +00005690 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005691 } else if (op == 4 || op == 6) {
5692 /* Narrowing operation. */
Peter Maydell7d1b0092011-03-06 21:39:54 +00005693 tmp = tcg_temp_new_i32();
Riku Voipio79b0e532010-02-05 15:52:28 +00005694 if (!u) {
pbrook9ee6e8b2007-11-11 00:04:49 +00005695 switch (size) {
pbrookad694712008-03-31 03:48:30 +00005696 case 0:
5697 gen_helper_neon_narrow_high_u8(tmp, cpu_V0);
5698 break;
5699 case 1:
5700 gen_helper_neon_narrow_high_u16(tmp, cpu_V0);
5701 break;
5702 case 2:
5703 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
5704 tcg_gen_trunc_i64_i32(tmp, cpu_V0);
5705 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005706 default: abort();
5707 }
5708 } else {
5709 switch (size) {
pbrookad694712008-03-31 03:48:30 +00005710 case 0:
5711 gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0);
5712 break;
5713 case 1:
5714 gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0);
5715 break;
5716 case 2:
5717 tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31);
5718 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
5719 tcg_gen_trunc_i64_i32(tmp, cpu_V0);
5720 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005721 default: abort();
5722 }
5723 }
pbrookad694712008-03-31 03:48:30 +00005724 if (pass == 0) {
5725 tmp3 = tmp;
5726 } else {
5727 neon_store_reg(rd, 0, tmp3);
5728 neon_store_reg(rd, 1, tmp);
5729 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005730 } else {
5731 /* Write back the result. */
pbrookad694712008-03-31 03:48:30 +00005732 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005733 }
5734 }
5735 } else {
Peter Maydell3e3326d2011-04-11 16:26:18 +01005736 /* Two registers and a scalar. NB that for ops of this form
5737 * the ARM ARM labels bit 24 as Q, but it is in our variable
5738 * 'u', not 'q'.
5739 */
5740 if (size == 0) {
5741 return 1;
5742 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005743 switch (op) {
pbrook9ee6e8b2007-11-11 00:04:49 +00005744 case 1: /* Float VMLA scalar */
pbrook9ee6e8b2007-11-11 00:04:49 +00005745 case 5: /* Floating point VMLS scalar */
pbrook9ee6e8b2007-11-11 00:04:49 +00005746 case 9: /* Floating point VMUL scalar */
Peter Maydell3e3326d2011-04-11 16:26:18 +01005747 if (size == 1) {
5748 return 1;
5749 }
5750 /* fall through */
5751 case 0: /* Integer VMLA scalar */
5752 case 4: /* Integer VMLS scalar */
5753 case 8: /* Integer VMUL scalar */
pbrook9ee6e8b2007-11-11 00:04:49 +00005754 case 12: /* VQDMULH scalar */
5755 case 13: /* VQRDMULH scalar */
Peter Maydell3e3326d2011-04-11 16:26:18 +01005756 if (u && ((rd | rn) & 1)) {
5757 return 1;
5758 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02005759 tmp = neon_get_scalar(size, rm);
5760 neon_store_scratch(0, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005761 for (pass = 0; pass < (u ? 4 : 2); pass++) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005762 tmp = neon_load_scratch(0);
5763 tmp2 = neon_load_reg(rn, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005764 if (op == 12) {
5765 if (size == 1) {
Peter Maydell02da0b22011-05-25 13:31:02 +00005766 gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005767 } else {
Peter Maydell02da0b22011-05-25 13:31:02 +00005768 gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005769 }
5770 } else if (op == 13) {
5771 if (size == 1) {
Peter Maydell02da0b22011-05-25 13:31:02 +00005772 gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005773 } else {
Peter Maydell02da0b22011-05-25 13:31:02 +00005774 gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005775 }
5776 } else if (op & 1) {
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005777 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
5778 gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
5779 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005780 } else {
5781 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005782 case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
5783 case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
5784 case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
Peter Maydell3e3326d2011-04-11 16:26:18 +01005785 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00005786 }
5787 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00005788 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005789 if (op < 8) {
5790 /* Accumulate. */
Filip Navaradd8fbd72009-10-15 13:07:14 +02005791 tmp2 = neon_load_reg(rd, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005792 switch (op) {
5793 case 0:
Filip Navaradd8fbd72009-10-15 13:07:14 +02005794 gen_neon_add(size, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005795 break;
5796 case 1:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005797 {
5798 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
5799 gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
5800 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005801 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005802 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005803 case 4:
Filip Navaradd8fbd72009-10-15 13:07:14 +02005804 gen_neon_rsb(size, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005805 break;
5806 case 5:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005807 {
5808 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
5809 gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
5810 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00005811 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00005812 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005813 default:
5814 abort();
5815 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00005816 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005817 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02005818 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005819 }
5820 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005821 case 3: /* VQDMLAL scalar */
pbrook9ee6e8b2007-11-11 00:04:49 +00005822 case 7: /* VQDMLSL scalar */
pbrook9ee6e8b2007-11-11 00:04:49 +00005823 case 11: /* VQDMULL scalar */
Peter Maydell3e3326d2011-04-11 16:26:18 +01005824 if (u == 1) {
pbrookad694712008-03-31 03:48:30 +00005825 return 1;
Peter Maydell3e3326d2011-04-11 16:26:18 +01005826 }
5827 /* fall through */
5828 case 2: /* VMLAL sclar */
5829 case 6: /* VMLSL scalar */
5830 case 10: /* VMULL scalar */
5831 if (rd & 1) {
5832 return 1;
5833 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02005834 tmp2 = neon_get_scalar(size, rm);
Christophe Lyonc6067f02011-01-19 15:37:58 +01005835 /* We need a copy of tmp2 because gen_neon_mull
5836 * deletes it during pass 0. */
Peter Maydell7d1b0092011-03-06 21:39:54 +00005837 tmp4 = tcg_temp_new_i32();
Christophe Lyonc6067f02011-01-19 15:37:58 +01005838 tcg_gen_mov_i32(tmp4, tmp2);
Filip Navaradd8fbd72009-10-15 13:07:14 +02005839 tmp3 = neon_load_reg(rn, 1);
pbrookad694712008-03-31 03:48:30 +00005840
pbrook9ee6e8b2007-11-11 00:04:49 +00005841 for (pass = 0; pass < 2; pass++) {
pbrookad694712008-03-31 03:48:30 +00005842 if (pass == 0) {
5843 tmp = neon_load_reg(rn, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005844 } else {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005845 tmp = tmp3;
Christophe Lyonc6067f02011-01-19 15:37:58 +01005846 tmp2 = tmp4;
pbrook9ee6e8b2007-11-11 00:04:49 +00005847 }
pbrookad694712008-03-31 03:48:30 +00005848 gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
pbrookad694712008-03-31 03:48:30 +00005849 if (op != 11) {
5850 neon_load_reg64(cpu_V1, rd + pass);
5851 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005852 switch (op) {
Peter Maydell4dc064e2011-02-11 12:26:48 +00005853 case 6:
5854 gen_neon_negl(cpu_V0, size);
5855 /* Fall through */
5856 case 2:
pbrookad694712008-03-31 03:48:30 +00005857 gen_neon_addl(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005858 break;
5859 case 3: case 7:
pbrookad694712008-03-31 03:48:30 +00005860 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
Peter Maydell4dc064e2011-02-11 12:26:48 +00005861 if (op == 7) {
5862 gen_neon_negl(cpu_V0, size);
5863 }
pbrookad694712008-03-31 03:48:30 +00005864 gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005865 break;
5866 case 10:
5867 /* no-op */
5868 break;
5869 case 11:
pbrookad694712008-03-31 03:48:30 +00005870 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005871 break;
5872 default:
5873 abort();
5874 }
pbrookad694712008-03-31 03:48:30 +00005875 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005876 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02005877
Filip Navaradd8fbd72009-10-15 13:07:14 +02005878
pbrook9ee6e8b2007-11-11 00:04:49 +00005879 break;
5880 default: /* 14 and 15 are RESERVED */
5881 return 1;
5882 }
5883 }
5884 } else { /* size == 3 */
5885 if (!u) {
5886 /* Extract. */
pbrook9ee6e8b2007-11-11 00:04:49 +00005887 imm = (insn >> 8) & 0xf;
pbrookad694712008-03-31 03:48:30 +00005888
5889 if (imm > 7 && !q)
5890 return 1;
5891
Peter Maydell52579ea2011-04-11 16:26:19 +01005892 if (q && ((rd | rn | rm) & 1)) {
5893 return 1;
5894 }
5895
pbrookad694712008-03-31 03:48:30 +00005896 if (imm == 0) {
5897 neon_load_reg64(cpu_V0, rn);
5898 if (q) {
5899 neon_load_reg64(cpu_V1, rn + 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005900 }
pbrookad694712008-03-31 03:48:30 +00005901 } else if (imm == 8) {
5902 neon_load_reg64(cpu_V0, rn + 1);
5903 if (q) {
5904 neon_load_reg64(cpu_V1, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00005905 }
pbrookad694712008-03-31 03:48:30 +00005906 } else if (q) {
pbrooka7812ae2008-11-17 14:43:54 +00005907 tmp64 = tcg_temp_new_i64();
pbrookad694712008-03-31 03:48:30 +00005908 if (imm < 8) {
5909 neon_load_reg64(cpu_V0, rn);
pbrooka7812ae2008-11-17 14:43:54 +00005910 neon_load_reg64(tmp64, rn + 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005911 } else {
pbrookad694712008-03-31 03:48:30 +00005912 neon_load_reg64(cpu_V0, rn + 1);
pbrooka7812ae2008-11-17 14:43:54 +00005913 neon_load_reg64(tmp64, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00005914 }
pbrookad694712008-03-31 03:48:30 +00005915 tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);
pbrooka7812ae2008-11-17 14:43:54 +00005916 tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8));
pbrookad694712008-03-31 03:48:30 +00005917 tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
5918 if (imm < 8) {
5919 neon_load_reg64(cpu_V1, rm);
5920 } else {
5921 neon_load_reg64(cpu_V1, rm + 1);
5922 imm -= 8;
5923 }
5924 tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
pbrooka7812ae2008-11-17 14:43:54 +00005925 tcg_gen_shri_i64(tmp64, tmp64, imm * 8);
5926 tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03005927 tcg_temp_free_i64(tmp64);
pbrookad694712008-03-31 03:48:30 +00005928 } else {
pbrooka7812ae2008-11-17 14:43:54 +00005929 /* BUGFIX */
pbrookad694712008-03-31 03:48:30 +00005930 neon_load_reg64(cpu_V0, rn);
pbrooka7812ae2008-11-17 14:43:54 +00005931 tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8);
pbrookad694712008-03-31 03:48:30 +00005932 neon_load_reg64(cpu_V1, rm);
pbrooka7812ae2008-11-17 14:43:54 +00005933 tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
pbrookad694712008-03-31 03:48:30 +00005934 tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
5935 }
5936 neon_store_reg64(cpu_V0, rd);
5937 if (q) {
5938 neon_store_reg64(cpu_V1, rd + 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005939 }
5940 } else if ((insn & (1 << 11)) == 0) {
5941 /* Two register misc. */
5942 op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
5943 size = (insn >> 18) & 3;
Peter Maydell600b8282011-04-11 16:26:20 +01005944 /* UNDEF for unknown op values and bad op-size combinations */
5945 if ((neon_2rm_sizes[op] & (1 << size)) == 0) {
5946 return 1;
5947 }
Peter Maydellfc2a9b32011-04-11 16:26:21 +01005948 if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&
5949 q && ((rm | rd) & 1)) {
5950 return 1;
5951 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005952 switch (op) {
Peter Maydell600b8282011-04-11 16:26:20 +01005953 case NEON_2RM_VREV64:
pbrook9ee6e8b2007-11-11 00:04:49 +00005954 for (pass = 0; pass < (q ? 2 : 1); pass++) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005955 tmp = neon_load_reg(rm, pass * 2);
5956 tmp2 = neon_load_reg(rm, pass * 2 + 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005957 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005958 case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
5959 case 1: gen_swap_half(tmp); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005960 case 2: /* no-op */ break;
5961 default: abort();
5962 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02005963 neon_store_reg(rd, pass * 2 + 1, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005964 if (size == 2) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005965 neon_store_reg(rd, pass * 2, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005966 } else {
pbrook9ee6e8b2007-11-11 00:04:49 +00005967 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02005968 case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break;
5969 case 1: gen_swap_half(tmp2); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005970 default: abort();
5971 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02005972 neon_store_reg(rd, pass * 2, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005973 }
5974 }
5975 break;
Peter Maydell600b8282011-04-11 16:26:20 +01005976 case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
5977 case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
pbrookad694712008-03-31 03:48:30 +00005978 for (pass = 0; pass < q + 1; pass++) {
5979 tmp = neon_load_reg(rm, pass * 2);
5980 gen_neon_widen(cpu_V0, tmp, size, op & 1);
5981 tmp = neon_load_reg(rm, pass * 2 + 1);
5982 gen_neon_widen(cpu_V1, tmp, size, op & 1);
5983 switch (size) {
5984 case 0: gen_helper_neon_paddl_u16(CPU_V001); break;
5985 case 1: gen_helper_neon_paddl_u32(CPU_V001); break;
5986 case 2: tcg_gen_add_i64(CPU_V001); break;
5987 default: abort();
5988 }
Peter Maydell600b8282011-04-11 16:26:20 +01005989 if (op >= NEON_2RM_VPADAL) {
pbrook9ee6e8b2007-11-11 00:04:49 +00005990 /* Accumulate. */
pbrookad694712008-03-31 03:48:30 +00005991 neon_load_reg64(cpu_V1, rd + pass);
5992 gen_neon_addl(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005993 }
pbrookad694712008-03-31 03:48:30 +00005994 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005995 }
5996 break;
Peter Maydell600b8282011-04-11 16:26:20 +01005997 case NEON_2RM_VTRN:
pbrook9ee6e8b2007-11-11 00:04:49 +00005998 if (size == 2) {
Juha Riihimäkia5a14942011-04-11 16:26:13 +01005999 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +00006000 for (n = 0; n < (q ? 4 : 2); n += 2) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006001 tmp = neon_load_reg(rm, n);
6002 tmp2 = neon_load_reg(rd, n + 1);
6003 neon_store_reg(rm, n, tmp2);
6004 neon_store_reg(rd, n + 1, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006005 }
6006 } else {
6007 goto elementwise;
6008 }
6009 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006010 case NEON_2RM_VUZP:
Peter Maydell02acedf2011-02-14 10:22:48 +00006011 if (gen_neon_unzip(rd, rm, size, q)) {
pbrook9ee6e8b2007-11-11 00:04:49 +00006012 return 1;
pbrook9ee6e8b2007-11-11 00:04:49 +00006013 }
6014 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006015 case NEON_2RM_VZIP:
Peter Maydelld68a6f32011-02-14 10:22:49 +00006016 if (gen_neon_zip(rd, rm, size, q)) {
pbrook9ee6e8b2007-11-11 00:04:49 +00006017 return 1;
pbrook9ee6e8b2007-11-11 00:04:49 +00006018 }
6019 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006020 case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
6021 /* also VQMOVUN; op field and mnemonics don't line up */
Peter Maydellfc2a9b32011-04-11 16:26:21 +01006022 if (rm & 1) {
6023 return 1;
6024 }
pbrooka50f5b92008-06-29 15:25:29 +00006025 TCGV_UNUSED(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006026 for (pass = 0; pass < 2; pass++) {
pbrookad694712008-03-31 03:48:30 +00006027 neon_load_reg64(cpu_V0, rm + pass);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006028 tmp = tcg_temp_new_i32();
Peter Maydell600b8282011-04-11 16:26:20 +01006029 gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size,
6030 tmp, cpu_V0);
pbrookad694712008-03-31 03:48:30 +00006031 if (pass == 0) {
6032 tmp2 = tmp;
6033 } else {
6034 neon_store_reg(rd, 0, tmp2);
6035 neon_store_reg(rd, 1, tmp);
6036 }
pbrook9ee6e8b2007-11-11 00:04:49 +00006037 }
6038 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006039 case NEON_2RM_VSHLL:
Peter Maydellfc2a9b32011-04-11 16:26:21 +01006040 if (q || (rd & 1)) {
pbrook9ee6e8b2007-11-11 00:04:49 +00006041 return 1;
Peter Maydell600b8282011-04-11 16:26:20 +01006042 }
pbrookad694712008-03-31 03:48:30 +00006043 tmp = neon_load_reg(rm, 0);
6044 tmp2 = neon_load_reg(rm, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00006045 for (pass = 0; pass < 2; pass++) {
pbrookad694712008-03-31 03:48:30 +00006046 if (pass == 1)
6047 tmp = tmp2;
6048 gen_neon_widen(cpu_V0, tmp, size, 1);
Juha Riihimäki30d11a22010-02-05 15:52:29 +00006049 tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size);
pbrookad694712008-03-31 03:48:30 +00006050 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00006051 }
6052 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006053 case NEON_2RM_VCVT_F16_F32:
Peter Maydellfc2a9b32011-04-11 16:26:21 +01006054 if (!arm_feature(env, ARM_FEATURE_VFP_FP16) ||
6055 q || (rm & 1)) {
6056 return 1;
6057 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00006058 tmp = tcg_temp_new_i32();
6059 tmp2 = tcg_temp_new_i32();
Paul Brook60011492009-11-19 16:45:20 +00006060 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
Peter Maydell2d981da2011-02-10 11:29:01 +00006061 gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
Paul Brook60011492009-11-19 16:45:20 +00006062 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
Peter Maydell2d981da2011-02-10 11:29:01 +00006063 gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
Paul Brook60011492009-11-19 16:45:20 +00006064 tcg_gen_shli_i32(tmp2, tmp2, 16);
6065 tcg_gen_or_i32(tmp2, tmp2, tmp);
6066 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));
Peter Maydell2d981da2011-02-10 11:29:01 +00006067 gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
Paul Brook60011492009-11-19 16:45:20 +00006068 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
6069 neon_store_reg(rd, 0, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006070 tmp2 = tcg_temp_new_i32();
Peter Maydell2d981da2011-02-10 11:29:01 +00006071 gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
Paul Brook60011492009-11-19 16:45:20 +00006072 tcg_gen_shli_i32(tmp2, tmp2, 16);
6073 tcg_gen_or_i32(tmp2, tmp2, tmp);
6074 neon_store_reg(rd, 1, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006075 tcg_temp_free_i32(tmp);
Paul Brook60011492009-11-19 16:45:20 +00006076 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006077 case NEON_2RM_VCVT_F32_F16:
Peter Maydellfc2a9b32011-04-11 16:26:21 +01006078 if (!arm_feature(env, ARM_FEATURE_VFP_FP16) ||
6079 q || (rd & 1)) {
6080 return 1;
6081 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00006082 tmp3 = tcg_temp_new_i32();
Paul Brook60011492009-11-19 16:45:20 +00006083 tmp = neon_load_reg(rm, 0);
6084 tmp2 = neon_load_reg(rm, 1);
6085 tcg_gen_ext16u_i32(tmp3, tmp);
Peter Maydell2d981da2011-02-10 11:29:01 +00006086 gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
Paul Brook60011492009-11-19 16:45:20 +00006087 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
6088 tcg_gen_shri_i32(tmp3, tmp, 16);
Peter Maydell2d981da2011-02-10 11:29:01 +00006089 gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
Paul Brook60011492009-11-19 16:45:20 +00006090 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
Peter Maydell7d1b0092011-03-06 21:39:54 +00006091 tcg_temp_free_i32(tmp);
Paul Brook60011492009-11-19 16:45:20 +00006092 tcg_gen_ext16u_i32(tmp3, tmp2);
Peter Maydell2d981da2011-02-10 11:29:01 +00006093 gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
Paul Brook60011492009-11-19 16:45:20 +00006094 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
6095 tcg_gen_shri_i32(tmp3, tmp2, 16);
Peter Maydell2d981da2011-02-10 11:29:01 +00006096 gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
Paul Brook60011492009-11-19 16:45:20 +00006097 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
Peter Maydell7d1b0092011-03-06 21:39:54 +00006098 tcg_temp_free_i32(tmp2);
6099 tcg_temp_free_i32(tmp3);
Paul Brook60011492009-11-19 16:45:20 +00006100 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00006101 default:
6102 elementwise:
6103 for (pass = 0; pass < (q ? 4 : 2); pass++) {
Peter Maydell600b8282011-04-11 16:26:20 +01006104 if (neon_2rm_is_float_op(op)) {
pbrook4373f3c2008-03-31 03:47:19 +00006105 tcg_gen_ld_f32(cpu_F0s, cpu_env,
6106 neon_reg_offset(rm, pass));
Filip Navaradd8fbd72009-10-15 13:07:14 +02006107 TCGV_UNUSED(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006108 } else {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006109 tmp = neon_load_reg(rm, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00006110 }
6111 switch (op) {
Peter Maydell600b8282011-04-11 16:26:20 +01006112 case NEON_2RM_VREV32:
pbrook9ee6e8b2007-11-11 00:04:49 +00006113 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006114 case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
6115 case 1: gen_swap_half(tmp); break;
Peter Maydell600b8282011-04-11 16:26:20 +01006116 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006117 }
6118 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006119 case NEON_2RM_VREV16:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006120 gen_rev16(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006121 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006122 case NEON_2RM_VCLS:
pbrook9ee6e8b2007-11-11 00:04:49 +00006123 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006124 case 0: gen_helper_neon_cls_s8(tmp, tmp); break;
6125 case 1: gen_helper_neon_cls_s16(tmp, tmp); break;
6126 case 2: gen_helper_neon_cls_s32(tmp, tmp); break;
Peter Maydell600b8282011-04-11 16:26:20 +01006127 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006128 }
6129 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006130 case NEON_2RM_VCLZ:
pbrook9ee6e8b2007-11-11 00:04:49 +00006131 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006132 case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
6133 case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
6134 case 2: gen_helper_clz(tmp, tmp); break;
Peter Maydell600b8282011-04-11 16:26:20 +01006135 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006136 }
6137 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006138 case NEON_2RM_VCNT:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006139 gen_helper_neon_cnt_u8(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006140 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006141 case NEON_2RM_VMVN:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006142 tcg_gen_not_i32(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006143 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006144 case NEON_2RM_VQABS:
pbrook9ee6e8b2007-11-11 00:04:49 +00006145 switch (size) {
Peter Maydell02da0b22011-05-25 13:31:02 +00006146 case 0:
6147 gen_helper_neon_qabs_s8(tmp, cpu_env, tmp);
6148 break;
6149 case 1:
6150 gen_helper_neon_qabs_s16(tmp, cpu_env, tmp);
6151 break;
6152 case 2:
6153 gen_helper_neon_qabs_s32(tmp, cpu_env, tmp);
6154 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006155 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006156 }
6157 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006158 case NEON_2RM_VQNEG:
pbrook9ee6e8b2007-11-11 00:04:49 +00006159 switch (size) {
Peter Maydell02da0b22011-05-25 13:31:02 +00006160 case 0:
6161 gen_helper_neon_qneg_s8(tmp, cpu_env, tmp);
6162 break;
6163 case 1:
6164 gen_helper_neon_qneg_s16(tmp, cpu_env, tmp);
6165 break;
6166 case 2:
6167 gen_helper_neon_qneg_s32(tmp, cpu_env, tmp);
6168 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006169 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006170 }
6171 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006172 case NEON_2RM_VCGT0: case NEON_2RM_VCLE0:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006173 tmp2 = tcg_const_i32(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006174 switch(size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006175 case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break;
6176 case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break;
6177 case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break;
Peter Maydell600b8282011-04-11 16:26:20 +01006178 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006179 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02006180 tcg_temp_free(tmp2);
Peter Maydell600b8282011-04-11 16:26:20 +01006181 if (op == NEON_2RM_VCLE0) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006182 tcg_gen_not_i32(tmp, tmp);
Peter Maydell600b8282011-04-11 16:26:20 +01006183 }
pbrook9ee6e8b2007-11-11 00:04:49 +00006184 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006185 case NEON_2RM_VCGE0: case NEON_2RM_VCLT0:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006186 tmp2 = tcg_const_i32(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006187 switch(size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006188 case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break;
6189 case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break;
6190 case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break;
Peter Maydell600b8282011-04-11 16:26:20 +01006191 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006192 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02006193 tcg_temp_free(tmp2);
Peter Maydell600b8282011-04-11 16:26:20 +01006194 if (op == NEON_2RM_VCLT0) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006195 tcg_gen_not_i32(tmp, tmp);
Peter Maydell600b8282011-04-11 16:26:20 +01006196 }
pbrook9ee6e8b2007-11-11 00:04:49 +00006197 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006198 case NEON_2RM_VCEQ0:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006199 tmp2 = tcg_const_i32(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006200 switch(size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006201 case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
6202 case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
6203 case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
Peter Maydell600b8282011-04-11 16:26:20 +01006204 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006205 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02006206 tcg_temp_free(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006207 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006208 case NEON_2RM_VABS:
pbrook9ee6e8b2007-11-11 00:04:49 +00006209 switch(size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006210 case 0: gen_helper_neon_abs_s8(tmp, tmp); break;
6211 case 1: gen_helper_neon_abs_s16(tmp, tmp); break;
6212 case 2: tcg_gen_abs_i32(tmp, tmp); break;
Peter Maydell600b8282011-04-11 16:26:20 +01006213 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006214 }
6215 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006216 case NEON_2RM_VNEG:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006217 tmp2 = tcg_const_i32(0);
6218 gen_neon_rsb(size, tmp, tmp2);
6219 tcg_temp_free(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006220 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006221 case NEON_2RM_VCGT0_F:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006222 {
6223 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
Filip Navaradd8fbd72009-10-15 13:07:14 +02006224 tmp2 = tcg_const_i32(0);
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006225 gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
Filip Navaradd8fbd72009-10-15 13:07:14 +02006226 tcg_temp_free(tmp2);
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006227 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00006228 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006229 }
Peter Maydell600b8282011-04-11 16:26:20 +01006230 case NEON_2RM_VCGE0_F:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006231 {
6232 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
Filip Navaradd8fbd72009-10-15 13:07:14 +02006233 tmp2 = tcg_const_i32(0);
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006234 gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
Filip Navaradd8fbd72009-10-15 13:07:14 +02006235 tcg_temp_free(tmp2);
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006236 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00006237 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006238 }
Peter Maydell600b8282011-04-11 16:26:20 +01006239 case NEON_2RM_VCEQ0_F:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006240 {
6241 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
Filip Navaradd8fbd72009-10-15 13:07:14 +02006242 tmp2 = tcg_const_i32(0);
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006243 gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
Filip Navaradd8fbd72009-10-15 13:07:14 +02006244 tcg_temp_free(tmp2);
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006245 tcg_temp_free_ptr(fpstatus);
pbrook9ee6e8b2007-11-11 00:04:49 +00006246 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006247 }
Peter Maydell600b8282011-04-11 16:26:20 +01006248 case NEON_2RM_VCLE0_F:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006249 {
6250 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
Peter Maydell0e326102011-03-11 08:12:23 +00006251 tmp2 = tcg_const_i32(0);
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006252 gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus);
Peter Maydell0e326102011-03-11 08:12:23 +00006253 tcg_temp_free(tmp2);
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006254 tcg_temp_free_ptr(fpstatus);
Peter Maydell0e326102011-03-11 08:12:23 +00006255 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006256 }
Peter Maydell600b8282011-04-11 16:26:20 +01006257 case NEON_2RM_VCLT0_F:
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006258 {
6259 TCGv_ptr fpstatus = get_fpstatus_ptr(1);
Peter Maydell0e326102011-03-11 08:12:23 +00006260 tmp2 = tcg_const_i32(0);
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006261 gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus);
Peter Maydell0e326102011-03-11 08:12:23 +00006262 tcg_temp_free(tmp2);
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006263 tcg_temp_free_ptr(fpstatus);
Peter Maydell0e326102011-03-11 08:12:23 +00006264 break;
Peter Maydellaa47cfd2011-05-25 13:49:19 +00006265 }
Peter Maydell600b8282011-04-11 16:26:20 +01006266 case NEON_2RM_VABS_F:
pbrook4373f3c2008-03-31 03:47:19 +00006267 gen_vfp_abs(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006268 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006269 case NEON_2RM_VNEG_F:
pbrook4373f3c2008-03-31 03:47:19 +00006270 gen_vfp_neg(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006271 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006272 case NEON_2RM_VSWP:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006273 tmp2 = neon_load_reg(rd, pass);
6274 neon_store_reg(rm, pass, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006275 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006276 case NEON_2RM_VTRN:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006277 tmp2 = neon_load_reg(rd, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00006278 switch (size) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006279 case 0: gen_neon_trn_u8(tmp, tmp2); break;
6280 case 1: gen_neon_trn_u16(tmp, tmp2); break;
Peter Maydell600b8282011-04-11 16:26:20 +01006281 default: abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006282 }
Filip Navaradd8fbd72009-10-15 13:07:14 +02006283 neon_store_reg(rm, pass, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006284 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006285 case NEON_2RM_VRECPE:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006286 gen_helper_recpe_u32(tmp, tmp, cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00006287 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006288 case NEON_2RM_VRSQRTE:
Filip Navaradd8fbd72009-10-15 13:07:14 +02006289 gen_helper_rsqrte_u32(tmp, tmp, cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00006290 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006291 case NEON_2RM_VRECPE_F:
pbrook4373f3c2008-03-31 03:47:19 +00006292 gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00006293 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006294 case NEON_2RM_VRSQRTE_F:
pbrook4373f3c2008-03-31 03:47:19 +00006295 gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00006296 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006297 case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
Peter Maydell5500b062011-05-19 14:46:19 +01006298 gen_vfp_sito(0, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00006299 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006300 case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */
Peter Maydell5500b062011-05-19 14:46:19 +01006301 gen_vfp_uito(0, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00006302 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006303 case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */
Peter Maydell5500b062011-05-19 14:46:19 +01006304 gen_vfp_tosiz(0, 1);
Peter Maydelld3587ef2010-12-07 15:37:34 +00006305 break;
Peter Maydell600b8282011-04-11 16:26:20 +01006306 case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */
Peter Maydell5500b062011-05-19 14:46:19 +01006307 gen_vfp_touiz(0, 1);
Peter Maydelld3587ef2010-12-07 15:37:34 +00006308 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00006309 default:
Peter Maydell600b8282011-04-11 16:26:20 +01006310 /* Reserved op values were caught by the
6311 * neon_2rm_sizes[] check earlier.
6312 */
6313 abort();
pbrook9ee6e8b2007-11-11 00:04:49 +00006314 }
Peter Maydell600b8282011-04-11 16:26:20 +01006315 if (neon_2rm_is_float_op(op)) {
pbrook4373f3c2008-03-31 03:47:19 +00006316 tcg_gen_st_f32(cpu_F0s, cpu_env,
6317 neon_reg_offset(rd, pass));
pbrook9ee6e8b2007-11-11 00:04:49 +00006318 } else {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006319 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006320 }
6321 }
6322 break;
6323 }
6324 } else if ((insn & (1 << 10)) == 0) {
6325 /* VTBL, VTBX. */
Peter Maydell56907d72011-04-11 16:26:22 +01006326 int n = ((insn >> 8) & 3) + 1;
6327 if ((rn + n) > 32) {
6328 /* This is UNPREDICTABLE; we choose to UNDEF to avoid the
6329 * helper function running off the end of the register file.
6330 */
6331 return 1;
6332 }
6333 n <<= 3;
pbrook9ee6e8b2007-11-11 00:04:49 +00006334 if (insn & (1 << 6)) {
pbrook8f8e3aa2008-03-31 03:48:01 +00006335 tmp = neon_load_reg(rd, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006336 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00006337 tmp = tcg_temp_new_i32();
pbrook8f8e3aa2008-03-31 03:48:01 +00006338 tcg_gen_movi_i32(tmp, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006339 }
pbrook8f8e3aa2008-03-31 03:48:01 +00006340 tmp2 = neon_load_reg(rm, 0);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03006341 tmp4 = tcg_const_i32(rn);
6342 tmp5 = tcg_const_i32(n);
6343 gen_helper_neon_tbl(tmp2, tmp2, tmp, tmp4, tmp5);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006344 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006345 if (insn & (1 << 6)) {
pbrook8f8e3aa2008-03-31 03:48:01 +00006346 tmp = neon_load_reg(rd, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00006347 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00006348 tmp = tcg_temp_new_i32();
pbrook8f8e3aa2008-03-31 03:48:01 +00006349 tcg_gen_movi_i32(tmp, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006350 }
pbrook8f8e3aa2008-03-31 03:48:01 +00006351 tmp3 = neon_load_reg(rm, 1);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03006352 gen_helper_neon_tbl(tmp3, tmp3, tmp, tmp4, tmp5);
Juha Riihimäki25aeb692009-10-26 13:02:37 +02006353 tcg_temp_free_i32(tmp5);
6354 tcg_temp_free_i32(tmp4);
pbrook8f8e3aa2008-03-31 03:48:01 +00006355 neon_store_reg(rd, 0, tmp2);
pbrook3018f252008-09-22 00:52:42 +00006356 neon_store_reg(rd, 1, tmp3);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006357 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006358 } else if ((insn & 0x380) == 0) {
6359 /* VDUP */
Juha Riihimäki133da6a2011-04-11 16:26:23 +01006360 if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {
6361 return 1;
6362 }
pbrook9ee6e8b2007-11-11 00:04:49 +00006363 if (insn & (1 << 19)) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006364 tmp = neon_load_reg(rm, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00006365 } else {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006366 tmp = neon_load_reg(rm, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006367 }
6368 if (insn & (1 << 16)) {
Filip Navaradd8fbd72009-10-15 13:07:14 +02006369 gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8);
pbrook9ee6e8b2007-11-11 00:04:49 +00006370 } else if (insn & (1 << 17)) {
6371 if ((insn >> 18) & 1)
Filip Navaradd8fbd72009-10-15 13:07:14 +02006372 gen_neon_dup_high16(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006373 else
Filip Navaradd8fbd72009-10-15 13:07:14 +02006374 gen_neon_dup_low16(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006375 }
6376 for (pass = 0; pass < (q ? 4 : 2); pass++) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00006377 tmp2 = tcg_temp_new_i32();
Filip Navaradd8fbd72009-10-15 13:07:14 +02006378 tcg_gen_mov_i32(tmp2, tmp);
6379 neon_store_reg(rd, pass, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006380 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00006381 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006382 } else {
6383 return 1;
6384 }
6385 }
6386 }
6387 return 0;
6388}
6389
pbrookfe1479c2008-12-19 13:18:36 +00006390static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn)
6391{
6392 int crn = (insn >> 16) & 0xf;
6393 int crm = insn & 0xf;
6394 int op1 = (insn >> 21) & 7;
6395 int op2 = (insn >> 5) & 7;
6396 int rt = (insn >> 12) & 0xf;
6397 TCGv tmp;
6398
Peter Maydellca27c052011-02-22 18:19:43 +00006399 /* Minimal set of debug registers, since we don't support debug */
6400 if (op1 == 0 && crn == 0 && op2 == 0) {
6401 switch (crm) {
6402 case 0:
6403 /* DBGDIDR: just RAZ. In particular this means the
6404 * "debug architecture version" bits will read as
6405 * a reserved value, which should cause Linux to
6406 * not try to use the debug hardware.
6407 */
6408 tmp = tcg_const_i32(0);
6409 store_reg(s, rt, tmp);
6410 return 0;
6411 case 1:
6412 case 2:
6413 /* DBGDRAR and DBGDSAR: v7 only. Always RAZ since we
6414 * don't implement memory mapped debug components
6415 */
6416 if (ENABLE_ARCH_7) {
6417 tmp = tcg_const_i32(0);
6418 store_reg(s, rt, tmp);
6419 return 0;
6420 }
6421 break;
6422 default:
6423 break;
6424 }
6425 }
6426
pbrookfe1479c2008-12-19 13:18:36 +00006427 if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
6428 if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
6429 /* TEECR */
6430 if (IS_USER(s))
6431 return 1;
6432 tmp = load_cpu_field(teecr);
6433 store_reg(s, rt, tmp);
6434 return 0;
6435 }
6436 if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
6437 /* TEEHBR */
6438 if (IS_USER(s) && (env->teecr & 1))
6439 return 1;
6440 tmp = load_cpu_field(teehbr);
6441 store_reg(s, rt, tmp);
6442 return 0;
6443 }
6444 }
pbrookfe1479c2008-12-19 13:18:36 +00006445 return 1;
6446}
6447
6448static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn)
6449{
6450 int crn = (insn >> 16) & 0xf;
6451 int crm = insn & 0xf;
6452 int op1 = (insn >> 21) & 7;
6453 int op2 = (insn >> 5) & 7;
6454 int rt = (insn >> 12) & 0xf;
6455 TCGv tmp;
6456
6457 if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
6458 if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
6459 /* TEECR */
6460 if (IS_USER(s))
6461 return 1;
6462 tmp = load_reg(s, rt);
6463 gen_helper_set_teecr(cpu_env, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006464 tcg_temp_free_i32(tmp);
pbrookfe1479c2008-12-19 13:18:36 +00006465 return 0;
6466 }
6467 if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
6468 /* TEEHBR */
6469 if (IS_USER(s) && (env->teecr & 1))
6470 return 1;
6471 tmp = load_reg(s, rt);
6472 store_cpu_field(tmp, teehbr);
6473 return 0;
6474 }
6475 }
pbrookfe1479c2008-12-19 13:18:36 +00006476 return 1;
6477}
6478
pbrook9ee6e8b2007-11-11 00:04:49 +00006479static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn)
6480{
6481 int cpnum;
6482
6483 cpnum = (insn >> 8) & 0xf;
6484 if (arm_feature(env, ARM_FEATURE_XSCALE)
6485 && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
6486 return 1;
6487
6488 switch (cpnum) {
6489 case 0:
6490 case 1:
6491 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
6492 return disas_iwmmxt_insn(env, s, insn);
6493 } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
6494 return disas_dsp_insn(env, s, insn);
6495 }
6496 return 1;
6497 case 10:
6498 case 11:
6499 return disas_vfp_insn (env, s, insn);
pbrookfe1479c2008-12-19 13:18:36 +00006500 case 14:
6501 /* Coprocessors 7-15 are architecturally reserved by ARM.
6502 Unfortunately Intel decided to ignore this. */
6503 if (arm_feature(env, ARM_FEATURE_XSCALE))
6504 goto board;
6505 if (insn & (1 << 20))
6506 return disas_cp14_read(env, s, insn);
6507 else
6508 return disas_cp14_write(env, s, insn);
pbrook9ee6e8b2007-11-11 00:04:49 +00006509 case 15:
6510 return disas_cp15_insn (env, s, insn);
6511 default:
pbrookfe1479c2008-12-19 13:18:36 +00006512 board:
pbrook9ee6e8b2007-11-11 00:04:49 +00006513 /* Unknown coprocessor. See if the board has hooked it. */
6514 return disas_cp_insn (env, s, insn);
6515 }
6516}
6517
pbrook5e3f8782008-03-31 03:47:34 +00006518
6519/* Store a 64-bit value to a register pair. Clobbers val. */
pbrooka7812ae2008-11-17 14:43:54 +00006520static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
pbrook5e3f8782008-03-31 03:47:34 +00006521{
6522 TCGv tmp;
Peter Maydell7d1b0092011-03-06 21:39:54 +00006523 tmp = tcg_temp_new_i32();
pbrook5e3f8782008-03-31 03:47:34 +00006524 tcg_gen_trunc_i64_i32(tmp, val);
6525 store_reg(s, rlow, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006526 tmp = tcg_temp_new_i32();
pbrook5e3f8782008-03-31 03:47:34 +00006527 tcg_gen_shri_i64(val, val, 32);
6528 tcg_gen_trunc_i64_i32(tmp, val);
6529 store_reg(s, rhigh, tmp);
6530}
6531
6532/* load a 32-bit value from a register and perform a 64-bit accumulate. */
pbrooka7812ae2008-11-17 14:43:54 +00006533static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
pbrook5e3f8782008-03-31 03:47:34 +00006534{
pbrooka7812ae2008-11-17 14:43:54 +00006535 TCGv_i64 tmp;
pbrook5e3f8782008-03-31 03:47:34 +00006536 TCGv tmp2;
6537
pbrook36aa55d2008-09-21 13:48:32 +00006538 /* Load value and extend to 64 bits. */
pbrooka7812ae2008-11-17 14:43:54 +00006539 tmp = tcg_temp_new_i64();
pbrook5e3f8782008-03-31 03:47:34 +00006540 tmp2 = load_reg(s, rlow);
6541 tcg_gen_extu_i32_i64(tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006542 tcg_temp_free_i32(tmp2);
pbrook5e3f8782008-03-31 03:47:34 +00006543 tcg_gen_add_i64(val, val, tmp);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03006544 tcg_temp_free_i64(tmp);
pbrook5e3f8782008-03-31 03:47:34 +00006545}
6546
6547/* load and add a 64-bit value from a register pair. */
pbrooka7812ae2008-11-17 14:43:54 +00006548static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
pbrook5e3f8782008-03-31 03:47:34 +00006549{
pbrooka7812ae2008-11-17 14:43:54 +00006550 TCGv_i64 tmp;
pbrook36aa55d2008-09-21 13:48:32 +00006551 TCGv tmpl;
6552 TCGv tmph;
pbrook5e3f8782008-03-31 03:47:34 +00006553
6554 /* Load 64-bit value rd:rn. */
pbrook36aa55d2008-09-21 13:48:32 +00006555 tmpl = load_reg(s, rlow);
6556 tmph = load_reg(s, rhigh);
pbrooka7812ae2008-11-17 14:43:54 +00006557 tmp = tcg_temp_new_i64();
pbrook36aa55d2008-09-21 13:48:32 +00006558 tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006559 tcg_temp_free_i32(tmpl);
6560 tcg_temp_free_i32(tmph);
pbrook5e3f8782008-03-31 03:47:34 +00006561 tcg_gen_add_i64(val, val, tmp);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03006562 tcg_temp_free_i64(tmp);
pbrook5e3f8782008-03-31 03:47:34 +00006563}
6564
6565/* Set N and Z flags from a 64-bit value. */
pbrooka7812ae2008-11-17 14:43:54 +00006566static void gen_logicq_cc(TCGv_i64 val)
pbrook5e3f8782008-03-31 03:47:34 +00006567{
Peter Maydell7d1b0092011-03-06 21:39:54 +00006568 TCGv tmp = tcg_temp_new_i32();
pbrook5e3f8782008-03-31 03:47:34 +00006569 gen_helper_logicq_cc(tmp, val);
pbrook6fbe23d2008-04-01 17:19:11 +00006570 gen_logic_CC(tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006571 tcg_temp_free_i32(tmp);
pbrook5e3f8782008-03-31 03:47:34 +00006572}
6573
Paul Brook426f5ab2009-11-22 21:35:13 +00006574/* Load/Store exclusive instructions are implemented by remembering
6575 the value/address loaded, and seeing if these are the same
6576 when the store is performed. This should be is sufficient to implement
6577 the architecturally mandated semantics, and avoids having to monitor
6578 regular stores.
6579
6580 In system emulation mode only one CPU will be running at once, so
6581 this sequence is effectively atomic. In user emulation mode we
6582 throw an exception and handle the atomic operation elsewhere. */
6583static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
6584 TCGv addr, int size)
6585{
6586 TCGv tmp;
6587
6588 switch (size) {
6589 case 0:
6590 tmp = gen_ld8u(addr, IS_USER(s));
6591 break;
6592 case 1:
6593 tmp = gen_ld16u(addr, IS_USER(s));
6594 break;
6595 case 2:
6596 case 3:
6597 tmp = gen_ld32(addr, IS_USER(s));
6598 break;
6599 default:
6600 abort();
6601 }
6602 tcg_gen_mov_i32(cpu_exclusive_val, tmp);
6603 store_reg(s, rt, tmp);
6604 if (size == 3) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00006605 TCGv tmp2 = tcg_temp_new_i32();
Peter Maydell2c9adbd2010-12-07 15:37:34 +00006606 tcg_gen_addi_i32(tmp2, addr, 4);
6607 tmp = gen_ld32(tmp2, IS_USER(s));
Peter Maydell7d1b0092011-03-06 21:39:54 +00006608 tcg_temp_free_i32(tmp2);
Paul Brook426f5ab2009-11-22 21:35:13 +00006609 tcg_gen_mov_i32(cpu_exclusive_high, tmp);
6610 store_reg(s, rt2, tmp);
6611 }
6612 tcg_gen_mov_i32(cpu_exclusive_addr, addr);
6613}
6614
6615static void gen_clrex(DisasContext *s)
6616{
6617 tcg_gen_movi_i32(cpu_exclusive_addr, -1);
6618}
6619
6620#ifdef CONFIG_USER_ONLY
6621static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
6622 TCGv addr, int size)
6623{
6624 tcg_gen_mov_i32(cpu_exclusive_test, addr);
6625 tcg_gen_movi_i32(cpu_exclusive_info,
6626 size | (rd << 4) | (rt << 8) | (rt2 << 12));
Peter Maydellbc4a0de2011-01-14 20:39:19 +01006627 gen_exception_insn(s, 4, EXCP_STREX);
Paul Brook426f5ab2009-11-22 21:35:13 +00006628}
6629#else
6630static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
6631 TCGv addr, int size)
6632{
6633 TCGv tmp;
6634 int done_label;
6635 int fail_label;
6636
6637 /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) {
6638 [addr] = {Rt};
6639 {Rd} = 0;
6640 } else {
6641 {Rd} = 1;
6642 } */
6643 fail_label = gen_new_label();
6644 done_label = gen_new_label();
6645 tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
6646 switch (size) {
6647 case 0:
6648 tmp = gen_ld8u(addr, IS_USER(s));
6649 break;
6650 case 1:
6651 tmp = gen_ld16u(addr, IS_USER(s));
6652 break;
6653 case 2:
6654 case 3:
6655 tmp = gen_ld32(addr, IS_USER(s));
6656 break;
6657 default:
6658 abort();
6659 }
6660 tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006661 tcg_temp_free_i32(tmp);
Paul Brook426f5ab2009-11-22 21:35:13 +00006662 if (size == 3) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00006663 TCGv tmp2 = tcg_temp_new_i32();
Paul Brook426f5ab2009-11-22 21:35:13 +00006664 tcg_gen_addi_i32(tmp2, addr, 4);
Peter Maydell2c9adbd2010-12-07 15:37:34 +00006665 tmp = gen_ld32(tmp2, IS_USER(s));
Peter Maydell7d1b0092011-03-06 21:39:54 +00006666 tcg_temp_free_i32(tmp2);
Paul Brook426f5ab2009-11-22 21:35:13 +00006667 tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006668 tcg_temp_free_i32(tmp);
Paul Brook426f5ab2009-11-22 21:35:13 +00006669 }
6670 tmp = load_reg(s, rt);
6671 switch (size) {
6672 case 0:
6673 gen_st8(tmp, addr, IS_USER(s));
6674 break;
6675 case 1:
6676 gen_st16(tmp, addr, IS_USER(s));
6677 break;
6678 case 2:
6679 case 3:
6680 gen_st32(tmp, addr, IS_USER(s));
6681 break;
6682 default:
6683 abort();
6684 }
6685 if (size == 3) {
6686 tcg_gen_addi_i32(addr, addr, 4);
6687 tmp = load_reg(s, rt2);
6688 gen_st32(tmp, addr, IS_USER(s));
6689 }
6690 tcg_gen_movi_i32(cpu_R[rd], 0);
6691 tcg_gen_br(done_label);
6692 gen_set_label(fail_label);
6693 tcg_gen_movi_i32(cpu_R[rd], 1);
6694 gen_set_label(done_label);
6695 tcg_gen_movi_i32(cpu_exclusive_addr, -1);
6696}
6697#endif
6698
bellardb7bcbe92005-02-22 19:27:29 +00006699static void disas_arm_insn(CPUState * env, DisasContext *s)
bellard2c0262a2003-09-30 20:34:21 +00006700{
6701 unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
pbrookb26eefb2008-03-31 03:44:26 +00006702 TCGv tmp;
pbrook36706692008-03-31 03:46:19 +00006703 TCGv tmp2;
pbrook6ddbc6e2008-03-31 03:46:33 +00006704 TCGv tmp3;
pbrookb0109802008-03-31 03:47:03 +00006705 TCGv addr;
pbrooka7812ae2008-11-17 14:43:54 +00006706 TCGv_i64 tmp64;
ths3b46e622007-09-17 08:09:54 +00006707
bellardb5ff1b32005-11-26 10:38:39 +00006708 insn = ldl_code(s->pc);
bellard2c0262a2003-09-30 20:34:21 +00006709 s->pc += 4;
ths3b46e622007-09-17 08:09:54 +00006710
pbrook9ee6e8b2007-11-11 00:04:49 +00006711 /* M variants do not implement ARM mode. */
6712 if (IS_M(env))
6713 goto illegal_op;
bellard2c0262a2003-09-30 20:34:21 +00006714 cond = insn >> 28;
bellard99c475a2005-01-31 20:45:13 +00006715 if (cond == 0xf){
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04006716 /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we
6717 * choose to UNDEF. In ARMv5 and above the space is used
6718 * for miscellaneous unconditional instructions.
6719 */
6720 ARCH(5);
6721
bellardb7bcbe92005-02-22 19:27:29 +00006722 /* Unconditional instructions. */
pbrook9ee6e8b2007-11-11 00:04:49 +00006723 if (((insn >> 25) & 7) == 1) {
6724 /* NEON Data processing. */
6725 if (!arm_feature(env, ARM_FEATURE_NEON))
6726 goto illegal_op;
6727
6728 if (disas_neon_data_insn(env, s, insn))
6729 goto illegal_op;
6730 return;
6731 }
6732 if ((insn & 0x0f100000) == 0x04000000) {
6733 /* NEON load/store. */
6734 if (!arm_feature(env, ARM_FEATURE_NEON))
6735 goto illegal_op;
6736
6737 if (disas_neon_ls_insn(env, s, insn))
6738 goto illegal_op;
6739 return;
6740 }
Peter Maydell3d185e52011-02-03 19:43:24 +00006741 if (((insn & 0x0f30f000) == 0x0510f000) ||
6742 ((insn & 0x0f30f010) == 0x0710f000)) {
6743 if ((insn & (1 << 22)) == 0) {
6744 /* PLDW; v7MP */
6745 if (!arm_feature(env, ARM_FEATURE_V7MP)) {
6746 goto illegal_op;
6747 }
6748 }
6749 /* Otherwise PLD; v5TE+ */
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04006750 ARCH(5TE);
Peter Maydell3d185e52011-02-03 19:43:24 +00006751 return;
6752 }
6753 if (((insn & 0x0f70f000) == 0x0450f000) ||
6754 ((insn & 0x0f70f010) == 0x0650f000)) {
6755 ARCH(7);
6756 return; /* PLI; V7 */
6757 }
6758 if (((insn & 0x0f700000) == 0x04100000) ||
6759 ((insn & 0x0f700010) == 0x06100000)) {
6760 if (!arm_feature(env, ARM_FEATURE_V7MP)) {
6761 goto illegal_op;
6762 }
6763 return; /* v7MP: Unallocated memory hint: must NOP */
6764 }
6765
6766 if ((insn & 0x0ffffdff) == 0x01010000) {
pbrook9ee6e8b2007-11-11 00:04:49 +00006767 ARCH(6);
6768 /* setend */
6769 if (insn & (1 << 9)) {
6770 /* BE8 mode not implemented. */
6771 goto illegal_op;
6772 }
6773 return;
6774 } else if ((insn & 0x0fffff00) == 0x057ff000) {
6775 switch ((insn >> 4) & 0xf) {
6776 case 1: /* clrex */
6777 ARCH(6K);
Paul Brook426f5ab2009-11-22 21:35:13 +00006778 gen_clrex(s);
pbrook9ee6e8b2007-11-11 00:04:49 +00006779 return;
6780 case 4: /* dsb */
6781 case 5: /* dmb */
6782 case 6: /* isb */
6783 ARCH(7);
6784 /* We don't emulate caches so these are a no-op. */
6785 return;
6786 default:
6787 goto illegal_op;
6788 }
6789 } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
6790 /* srs */
Filip Navarac67b6b72009-10-15 12:12:11 +02006791 int32_t offset;
pbrook9ee6e8b2007-11-11 00:04:49 +00006792 if (IS_USER(s))
6793 goto illegal_op;
6794 ARCH(6);
6795 op1 = (insn & 0x1f);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006796 addr = tcg_temp_new_i32();
Peter Maydell39ea3d42011-01-14 20:39:18 +01006797 tmp = tcg_const_i32(op1);
6798 gen_helper_get_r13_banked(addr, cpu_env, tmp);
6799 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006800 i = (insn >> 23) & 3;
6801 switch (i) {
6802 case 0: offset = -4; break; /* DA */
Filip Navarac67b6b72009-10-15 12:12:11 +02006803 case 1: offset = 0; break; /* IA */
6804 case 2: offset = -8; break; /* DB */
pbrook9ee6e8b2007-11-11 00:04:49 +00006805 case 3: offset = 4; break; /* IB */
6806 default: abort();
6807 }
6808 if (offset)
pbrookb0109802008-03-31 03:47:03 +00006809 tcg_gen_addi_i32(addr, addr, offset);
6810 tmp = load_reg(s, 14);
6811 gen_st32(tmp, addr, 0);
Filip Navarac67b6b72009-10-15 12:12:11 +02006812 tmp = load_cpu_field(spsr);
pbrookb0109802008-03-31 03:47:03 +00006813 tcg_gen_addi_i32(addr, addr, 4);
6814 gen_st32(tmp, addr, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006815 if (insn & (1 << 21)) {
6816 /* Base writeback. */
6817 switch (i) {
6818 case 0: offset = -8; break;
Filip Navarac67b6b72009-10-15 12:12:11 +02006819 case 1: offset = 4; break;
6820 case 2: offset = -4; break;
pbrook9ee6e8b2007-11-11 00:04:49 +00006821 case 3: offset = 0; break;
6822 default: abort();
6823 }
6824 if (offset)
Filip Navarac67b6b72009-10-15 12:12:11 +02006825 tcg_gen_addi_i32(addr, addr, offset);
Peter Maydell39ea3d42011-01-14 20:39:18 +01006826 tmp = tcg_const_i32(op1);
6827 gen_helper_set_r13_banked(cpu_env, tmp, addr);
6828 tcg_temp_free_i32(tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00006829 tcg_temp_free_i32(addr);
pbrookb0109802008-03-31 03:47:03 +00006830 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00006831 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00006832 }
Adam Lackorzynskia990f582010-03-01 17:19:54 +01006833 return;
Adam Lackorzynskiea825ee2010-03-02 01:17:35 +01006834 } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
pbrook9ee6e8b2007-11-11 00:04:49 +00006835 /* rfe */
Filip Navarac67b6b72009-10-15 12:12:11 +02006836 int32_t offset;
pbrook9ee6e8b2007-11-11 00:04:49 +00006837 if (IS_USER(s))
6838 goto illegal_op;
6839 ARCH(6);
6840 rn = (insn >> 16) & 0xf;
pbrookb0109802008-03-31 03:47:03 +00006841 addr = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00006842 i = (insn >> 23) & 3;
6843 switch (i) {
pbrookb0109802008-03-31 03:47:03 +00006844 case 0: offset = -4; break; /* DA */
Filip Navarac67b6b72009-10-15 12:12:11 +02006845 case 1: offset = 0; break; /* IA */
6846 case 2: offset = -8; break; /* DB */
pbrookb0109802008-03-31 03:47:03 +00006847 case 3: offset = 4; break; /* IB */
pbrook9ee6e8b2007-11-11 00:04:49 +00006848 default: abort();
6849 }
6850 if (offset)
pbrookb0109802008-03-31 03:47:03 +00006851 tcg_gen_addi_i32(addr, addr, offset);
6852 /* Load PC into tmp and CPSR into tmp2. */
6853 tmp = gen_ld32(addr, 0);
6854 tcg_gen_addi_i32(addr, addr, 4);
6855 tmp2 = gen_ld32(addr, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006856 if (insn & (1 << 21)) {
6857 /* Base writeback. */
6858 switch (i) {
pbrookb0109802008-03-31 03:47:03 +00006859 case 0: offset = -8; break;
Filip Navarac67b6b72009-10-15 12:12:11 +02006860 case 1: offset = 4; break;
6861 case 2: offset = -4; break;
pbrookb0109802008-03-31 03:47:03 +00006862 case 3: offset = 0; break;
pbrook9ee6e8b2007-11-11 00:04:49 +00006863 default: abort();
6864 }
6865 if (offset)
pbrookb0109802008-03-31 03:47:03 +00006866 tcg_gen_addi_i32(addr, addr, offset);
6867 store_reg(s, rn, addr);
6868 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00006869 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00006870 }
pbrookb0109802008-03-31 03:47:03 +00006871 gen_rfe(s, tmp, tmp2);
Filip Navarac67b6b72009-10-15 12:12:11 +02006872 return;
pbrook9ee6e8b2007-11-11 00:04:49 +00006873 } else if ((insn & 0x0e000000) == 0x0a000000) {
bellard99c475a2005-01-31 20:45:13 +00006874 /* branch link and change to thumb (blx <offset>) */
6875 int32_t offset;
6876
6877 val = (uint32_t)s->pc;
Peter Maydell7d1b0092011-03-06 21:39:54 +00006878 tmp = tcg_temp_new_i32();
pbrookd9ba4832008-03-31 03:46:50 +00006879 tcg_gen_movi_i32(tmp, val);
6880 store_reg(s, 14, tmp);
bellard99c475a2005-01-31 20:45:13 +00006881 /* Sign-extend the 24-bit offset */
6882 offset = (((int32_t)insn) << 8) >> 8;
6883 /* offset * 4 + bit24 * 2 + (thumb bit) */
6884 val += (offset << 2) | ((insn >> 23) & 2) | 1;
6885 /* pipeline offset */
6886 val += 4;
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04006887 /* protected by ARCH(5); above, near the start of uncond block */
pbrookd9ba4832008-03-31 03:46:50 +00006888 gen_bx_im(s, val);
bellard99c475a2005-01-31 20:45:13 +00006889 return;
balrog2e232132007-08-01 02:31:54 +00006890 } else if ((insn & 0x0e000f00) == 0x0c000100) {
6891 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
6892 /* iWMMXt register transfer. */
6893 if (env->cp15.c15_cpar & (1 << 1))
6894 if (!disas_iwmmxt_insn(env, s, insn))
6895 return;
6896 }
bellardb7bcbe92005-02-22 19:27:29 +00006897 } else if ((insn & 0x0fe00000) == 0x0c400000) {
6898 /* Coprocessor double register transfer. */
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04006899 ARCH(5TE);
bellardb7bcbe92005-02-22 19:27:29 +00006900 } else if ((insn & 0x0f000010) == 0x0e000010) {
6901 /* Additional coprocessor register transfer. */
balrog7997d922008-07-19 10:34:35 +00006902 } else if ((insn & 0x0ff10020) == 0x01000000) {
pbrook9ee6e8b2007-11-11 00:04:49 +00006903 uint32_t mask;
6904 uint32_t val;
bellardb5ff1b32005-11-26 10:38:39 +00006905 /* cps (privileged) */
pbrook9ee6e8b2007-11-11 00:04:49 +00006906 if (IS_USER(s))
6907 return;
6908 mask = val = 0;
6909 if (insn & (1 << 19)) {
6910 if (insn & (1 << 8))
6911 mask |= CPSR_A;
6912 if (insn & (1 << 7))
6913 mask |= CPSR_I;
6914 if (insn & (1 << 6))
6915 mask |= CPSR_F;
6916 if (insn & (1 << 18))
6917 val |= mask;
6918 }
balrog7997d922008-07-19 10:34:35 +00006919 if (insn & (1 << 17)) {
pbrook9ee6e8b2007-11-11 00:04:49 +00006920 mask |= CPSR_M;
6921 val |= (insn & 0x1f);
6922 }
6923 if (mask) {
Filip Navara2fbac542009-10-15 12:43:04 +02006924 gen_set_psr_im(s, mask, 0, val);
bellardb5ff1b32005-11-26 10:38:39 +00006925 }
6926 return;
bellard99c475a2005-01-31 20:45:13 +00006927 }
bellard2c0262a2003-09-30 20:34:21 +00006928 goto illegal_op;
bellard99c475a2005-01-31 20:45:13 +00006929 }
bellard2c0262a2003-09-30 20:34:21 +00006930 if (cond != 0xe) {
6931 /* if not always execute, we generate a conditional jump to
6932 next instruction */
bellarde50e6a22005-04-26 20:36:11 +00006933 s->condlabel = gen_new_label();
pbrookd9ba4832008-03-31 03:46:50 +00006934 gen_test_cc(cond ^ 1, s->condlabel);
bellarde50e6a22005-04-26 20:36:11 +00006935 s->condjmp = 1;
bellard2c0262a2003-09-30 20:34:21 +00006936 }
bellard99c475a2005-01-31 20:45:13 +00006937 if ((insn & 0x0f900000) == 0x03000000) {
pbrook9ee6e8b2007-11-11 00:04:49 +00006938 if ((insn & (1 << 21)) == 0) {
6939 ARCH(6T2);
6940 rd = (insn >> 12) & 0xf;
6941 val = ((insn >> 4) & 0xf000) | (insn & 0xfff);
6942 if ((insn & (1 << 22)) == 0) {
6943 /* MOVW */
Peter Maydell7d1b0092011-03-06 21:39:54 +00006944 tmp = tcg_temp_new_i32();
pbrook5e3f8782008-03-31 03:47:34 +00006945 tcg_gen_movi_i32(tmp, val);
pbrook9ee6e8b2007-11-11 00:04:49 +00006946 } else {
6947 /* MOVT */
pbrook5e3f8782008-03-31 03:47:34 +00006948 tmp = load_reg(s, rd);
pbrook86831432008-05-11 12:22:01 +00006949 tcg_gen_ext16u_i32(tmp, tmp);
pbrook5e3f8782008-03-31 03:47:34 +00006950 tcg_gen_ori_i32(tmp, tmp, val << 16);
pbrook9ee6e8b2007-11-11 00:04:49 +00006951 }
pbrook5e3f8782008-03-31 03:47:34 +00006952 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006953 } else {
6954 if (((insn >> 12) & 0xf) != 0xf)
6955 goto illegal_op;
6956 if (((insn >> 16) & 0xf) == 0) {
6957 gen_nop_hint(s, insn & 0xff);
6958 } else {
6959 /* CPSR = immediate */
6960 val = insn & 0xff;
6961 shift = ((insn >> 8) & 0xf) * 2;
6962 if (shift)
6963 val = (val >> shift) | (val << (32 - shift));
pbrook9ee6e8b2007-11-11 00:04:49 +00006964 i = ((insn & (1 << 22)) != 0);
Filip Navara2fbac542009-10-15 12:43:04 +02006965 if (gen_set_psr_im(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, val))
pbrook9ee6e8b2007-11-11 00:04:49 +00006966 goto illegal_op;
6967 }
6968 }
bellard99c475a2005-01-31 20:45:13 +00006969 } else if ((insn & 0x0f900000) == 0x01000000
6970 && (insn & 0x00000090) != 0x00000090) {
6971 /* miscellaneous instructions */
6972 op1 = (insn >> 21) & 3;
6973 sh = (insn >> 4) & 0xf;
6974 rm = insn & 0xf;
6975 switch (sh) {
6976 case 0x0: /* move program status register */
bellard99c475a2005-01-31 20:45:13 +00006977 if (op1 & 1) {
bellardb5ff1b32005-11-26 10:38:39 +00006978 /* PSR = reg */
Filip Navara2fbac542009-10-15 12:43:04 +02006979 tmp = load_reg(s, rm);
pbrook2ae23e72006-02-11 16:20:39 +00006980 i = ((op1 & 2) != 0);
Filip Navara2fbac542009-10-15 12:43:04 +02006981 if (gen_set_psr(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, tmp))
bellardb5ff1b32005-11-26 10:38:39 +00006982 goto illegal_op;
bellard99c475a2005-01-31 20:45:13 +00006983 } else {
pbrook2ae23e72006-02-11 16:20:39 +00006984 /* reg = PSR */
bellard99c475a2005-01-31 20:45:13 +00006985 rd = (insn >> 12) & 0xf;
bellardb5ff1b32005-11-26 10:38:39 +00006986 if (op1 & 2) {
6987 if (IS_USER(s))
6988 goto illegal_op;
pbrookd9ba4832008-03-31 03:46:50 +00006989 tmp = load_cpu_field(spsr);
bellardb5ff1b32005-11-26 10:38:39 +00006990 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00006991 tmp = tcg_temp_new_i32();
pbrookd9ba4832008-03-31 03:46:50 +00006992 gen_helper_cpsr_read(tmp);
bellardb5ff1b32005-11-26 10:38:39 +00006993 }
pbrookd9ba4832008-03-31 03:46:50 +00006994 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00006995 }
bellardb8a9e8f2005-02-07 23:10:07 +00006996 break;
bellard99c475a2005-01-31 20:45:13 +00006997 case 0x1:
6998 if (op1 == 1) {
6999 /* branch/exchange thumb (bx). */
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04007000 ARCH(4T);
pbrookd9ba4832008-03-31 03:46:50 +00007001 tmp = load_reg(s, rm);
7002 gen_bx(s, tmp);
bellard99c475a2005-01-31 20:45:13 +00007003 } else if (op1 == 3) {
7004 /* clz */
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04007005 ARCH(5);
bellard99c475a2005-01-31 20:45:13 +00007006 rd = (insn >> 12) & 0xf;
pbrook1497c962008-03-31 03:45:50 +00007007 tmp = load_reg(s, rm);
7008 gen_helper_clz(tmp, tmp);
7009 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00007010 } else {
7011 goto illegal_op;
7012 }
7013 break;
bellardb5ff1b32005-11-26 10:38:39 +00007014 case 0x2:
7015 if (op1 == 1) {
7016 ARCH(5J); /* bxj */
7017 /* Trivial implementation equivalent to bx. */
pbrookd9ba4832008-03-31 03:46:50 +00007018 tmp = load_reg(s, rm);
7019 gen_bx(s, tmp);
bellardb5ff1b32005-11-26 10:38:39 +00007020 } else {
7021 goto illegal_op;
7022 }
7023 break;
bellard99c475a2005-01-31 20:45:13 +00007024 case 0x3:
7025 if (op1 != 1)
7026 goto illegal_op;
7027
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04007028 ARCH(5);
bellard99c475a2005-01-31 20:45:13 +00007029 /* branch link/exchange thumb (blx) */
pbrookd9ba4832008-03-31 03:46:50 +00007030 tmp = load_reg(s, rm);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007031 tmp2 = tcg_temp_new_i32();
pbrookd9ba4832008-03-31 03:46:50 +00007032 tcg_gen_movi_i32(tmp2, s->pc);
7033 store_reg(s, 14, tmp2);
7034 gen_bx(s, tmp);
bellard99c475a2005-01-31 20:45:13 +00007035 break;
7036 case 0x5: /* saturating add/subtract */
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04007037 ARCH(5TE);
bellard99c475a2005-01-31 20:45:13 +00007038 rd = (insn >> 12) & 0xf;
7039 rn = (insn >> 16) & 0xf;
balrogb40d0352008-09-20 03:18:07 +00007040 tmp = load_reg(s, rm);
pbrook5e3f8782008-03-31 03:47:34 +00007041 tmp2 = load_reg(s, rn);
bellardff8263a2005-05-13 22:45:23 +00007042 if (op1 & 2)
pbrook5e3f8782008-03-31 03:47:34 +00007043 gen_helper_double_saturate(tmp2, tmp2);
bellard99c475a2005-01-31 20:45:13 +00007044 if (op1 & 1)
pbrook5e3f8782008-03-31 03:47:34 +00007045 gen_helper_sub_saturate(tmp, tmp, tmp2);
bellard99c475a2005-01-31 20:45:13 +00007046 else
pbrook5e3f8782008-03-31 03:47:34 +00007047 gen_helper_add_saturate(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007048 tcg_temp_free_i32(tmp2);
pbrook5e3f8782008-03-31 03:47:34 +00007049 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00007050 break;
Adam Lackorzynski49e14942010-12-07 12:01:44 +00007051 case 7:
7052 /* SMC instruction (op1 == 3)
7053 and undefined instructions (op1 == 0 || op1 == 2)
7054 will trap */
7055 if (op1 != 1) {
7056 goto illegal_op;
7057 }
7058 /* bkpt */
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04007059 ARCH(5);
Peter Maydellbc4a0de2011-01-14 20:39:19 +01007060 gen_exception_insn(s, 4, EXCP_BKPT);
pbrook06c949e2006-02-04 19:35:26 +00007061 break;
bellard99c475a2005-01-31 20:45:13 +00007062 case 0x8: /* signed multiply */
7063 case 0xa:
7064 case 0xc:
7065 case 0xe:
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04007066 ARCH(5TE);
bellard99c475a2005-01-31 20:45:13 +00007067 rs = (insn >> 8) & 0xf;
7068 rn = (insn >> 12) & 0xf;
7069 rd = (insn >> 16) & 0xf;
7070 if (op1 == 1) {
7071 /* (32 * 16) >> 16 */
pbrook5e3f8782008-03-31 03:47:34 +00007072 tmp = load_reg(s, rm);
7073 tmp2 = load_reg(s, rs);
bellard99c475a2005-01-31 20:45:13 +00007074 if (sh & 4)
pbrook5e3f8782008-03-31 03:47:34 +00007075 tcg_gen_sari_i32(tmp2, tmp2, 16);
bellard99c475a2005-01-31 20:45:13 +00007076 else
pbrook5e3f8782008-03-31 03:47:34 +00007077 gen_sxth(tmp2);
pbrooka7812ae2008-11-17 14:43:54 +00007078 tmp64 = gen_muls_i64_i32(tmp, tmp2);
7079 tcg_gen_shri_i64(tmp64, tmp64, 16);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007080 tmp = tcg_temp_new_i32();
pbrooka7812ae2008-11-17 14:43:54 +00007081 tcg_gen_trunc_i64_i32(tmp, tmp64);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03007082 tcg_temp_free_i64(tmp64);
bellard99c475a2005-01-31 20:45:13 +00007083 if ((sh & 2) == 0) {
pbrook5e3f8782008-03-31 03:47:34 +00007084 tmp2 = load_reg(s, rn);
7085 gen_helper_add_setq(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007086 tcg_temp_free_i32(tmp2);
bellard99c475a2005-01-31 20:45:13 +00007087 }
pbrook5e3f8782008-03-31 03:47:34 +00007088 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00007089 } else {
7090 /* 16 * 16 */
pbrook5e3f8782008-03-31 03:47:34 +00007091 tmp = load_reg(s, rm);
7092 tmp2 = load_reg(s, rs);
7093 gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007094 tcg_temp_free_i32(tmp2);
bellard99c475a2005-01-31 20:45:13 +00007095 if (op1 == 2) {
pbrooka7812ae2008-11-17 14:43:54 +00007096 tmp64 = tcg_temp_new_i64();
7097 tcg_gen_ext_i32_i64(tmp64, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007098 tcg_temp_free_i32(tmp);
pbrooka7812ae2008-11-17 14:43:54 +00007099 gen_addq(s, tmp64, rn, rd);
7100 gen_storeq_reg(s, rn, rd, tmp64);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03007101 tcg_temp_free_i64(tmp64);
bellard99c475a2005-01-31 20:45:13 +00007102 } else {
bellard99c475a2005-01-31 20:45:13 +00007103 if (op1 == 0) {
pbrook5e3f8782008-03-31 03:47:34 +00007104 tmp2 = load_reg(s, rn);
7105 gen_helper_add_setq(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007106 tcg_temp_free_i32(tmp2);
bellard99c475a2005-01-31 20:45:13 +00007107 }
pbrook5e3f8782008-03-31 03:47:34 +00007108 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00007109 }
7110 }
7111 break;
7112 default:
7113 goto illegal_op;
7114 }
7115 } else if (((insn & 0x0e000000) == 0 &&
7116 (insn & 0x00000090) != 0x90) ||
7117 ((insn & 0x0e000000) == (1 << 25))) {
bellard2c0262a2003-09-30 20:34:21 +00007118 int set_cc, logic_cc, shiftop;
ths3b46e622007-09-17 08:09:54 +00007119
bellard2c0262a2003-09-30 20:34:21 +00007120 op1 = (insn >> 21) & 0xf;
7121 set_cc = (insn >> 20) & 1;
7122 logic_cc = table_logic_cc[op1] & set_cc;
7123
7124 /* data processing instruction */
7125 if (insn & (1 << 25)) {
7126 /* immediate operand */
7127 val = insn & 0xff;
7128 shift = ((insn >> 8) & 0xf) * 2;
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007129 if (shift) {
bellard2c0262a2003-09-30 20:34:21 +00007130 val = (val >> shift) | (val << (32 - shift));
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007131 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00007132 tmp2 = tcg_temp_new_i32();
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007133 tcg_gen_movi_i32(tmp2, val);
7134 if (logic_cc && shift) {
7135 gen_set_CF_bit31(tmp2);
7136 }
bellard2c0262a2003-09-30 20:34:21 +00007137 } else {
7138 /* register */
7139 rm = (insn) & 0xf;
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007140 tmp2 = load_reg(s, rm);
bellard2c0262a2003-09-30 20:34:21 +00007141 shiftop = (insn >> 5) & 3;
7142 if (!(insn & (1 << 4))) {
7143 shift = (insn >> 7) & 0x1f;
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007144 gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
bellard2c0262a2003-09-30 20:34:21 +00007145 } else {
7146 rs = (insn >> 8) & 0xf;
pbrook8984bd22008-03-31 03:47:48 +00007147 tmp = load_reg(s, rs);
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007148 gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
bellard2c0262a2003-09-30 20:34:21 +00007149 }
7150 }
7151 if (op1 != 0x0f && op1 != 0x0d) {
7152 rn = (insn >> 16) & 0xf;
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007153 tmp = load_reg(s, rn);
7154 } else {
7155 TCGV_UNUSED(tmp);
bellard2c0262a2003-09-30 20:34:21 +00007156 }
7157 rd = (insn >> 12) & 0xf;
7158 switch(op1) {
7159 case 0x00:
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007160 tcg_gen_and_i32(tmp, tmp, tmp2);
7161 if (logic_cc) {
7162 gen_logic_CC(tmp);
7163 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007164 store_reg_bx(env, s, rd, tmp);
bellard2c0262a2003-09-30 20:34:21 +00007165 break;
7166 case 0x01:
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007167 tcg_gen_xor_i32(tmp, tmp, tmp2);
7168 if (logic_cc) {
7169 gen_logic_CC(tmp);
7170 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007171 store_reg_bx(env, s, rd, tmp);
bellard2c0262a2003-09-30 20:34:21 +00007172 break;
7173 case 0x02:
bellardb5ff1b32005-11-26 10:38:39 +00007174 if (set_cc && rd == 15) {
7175 /* SUBS r15, ... is used for exception return. */
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007176 if (IS_USER(s)) {
bellardb5ff1b32005-11-26 10:38:39 +00007177 goto illegal_op;
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007178 }
7179 gen_helper_sub_cc(tmp, tmp, tmp2);
7180 gen_exception_return(s, tmp);
bellardb5ff1b32005-11-26 10:38:39 +00007181 } else {
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007182 if (set_cc) {
7183 gen_helper_sub_cc(tmp, tmp, tmp2);
7184 } else {
7185 tcg_gen_sub_i32(tmp, tmp, tmp2);
7186 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007187 store_reg_bx(env, s, rd, tmp);
bellardb5ff1b32005-11-26 10:38:39 +00007188 }
bellard2c0262a2003-09-30 20:34:21 +00007189 break;
7190 case 0x03:
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007191 if (set_cc) {
7192 gen_helper_sub_cc(tmp, tmp2, tmp);
7193 } else {
7194 tcg_gen_sub_i32(tmp, tmp2, tmp);
7195 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007196 store_reg_bx(env, s, rd, tmp);
bellard2c0262a2003-09-30 20:34:21 +00007197 break;
7198 case 0x04:
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007199 if (set_cc) {
7200 gen_helper_add_cc(tmp, tmp, tmp2);
7201 } else {
7202 tcg_gen_add_i32(tmp, tmp, tmp2);
7203 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007204 store_reg_bx(env, s, rd, tmp);
bellard2c0262a2003-09-30 20:34:21 +00007205 break;
7206 case 0x05:
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007207 if (set_cc) {
7208 gen_helper_adc_cc(tmp, tmp, tmp2);
7209 } else {
7210 gen_add_carry(tmp, tmp, tmp2);
7211 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007212 store_reg_bx(env, s, rd, tmp);
bellard2c0262a2003-09-30 20:34:21 +00007213 break;
7214 case 0x06:
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007215 if (set_cc) {
7216 gen_helper_sbc_cc(tmp, tmp, tmp2);
7217 } else {
7218 gen_sub_carry(tmp, tmp, tmp2);
7219 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007220 store_reg_bx(env, s, rd, tmp);
bellard2c0262a2003-09-30 20:34:21 +00007221 break;
7222 case 0x07:
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007223 if (set_cc) {
7224 gen_helper_sbc_cc(tmp, tmp2, tmp);
7225 } else {
7226 gen_sub_carry(tmp, tmp2, tmp);
7227 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007228 store_reg_bx(env, s, rd, tmp);
bellard2c0262a2003-09-30 20:34:21 +00007229 break;
7230 case 0x08:
7231 if (set_cc) {
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007232 tcg_gen_and_i32(tmp, tmp, tmp2);
7233 gen_logic_CC(tmp);
bellard2c0262a2003-09-30 20:34:21 +00007234 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00007235 tcg_temp_free_i32(tmp);
bellard2c0262a2003-09-30 20:34:21 +00007236 break;
7237 case 0x09:
7238 if (set_cc) {
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007239 tcg_gen_xor_i32(tmp, tmp, tmp2);
7240 gen_logic_CC(tmp);
bellard2c0262a2003-09-30 20:34:21 +00007241 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00007242 tcg_temp_free_i32(tmp);
bellard2c0262a2003-09-30 20:34:21 +00007243 break;
7244 case 0x0a:
7245 if (set_cc) {
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007246 gen_helper_sub_cc(tmp, tmp, tmp2);
bellard2c0262a2003-09-30 20:34:21 +00007247 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00007248 tcg_temp_free_i32(tmp);
bellard2c0262a2003-09-30 20:34:21 +00007249 break;
7250 case 0x0b:
7251 if (set_cc) {
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007252 gen_helper_add_cc(tmp, tmp, tmp2);
bellard2c0262a2003-09-30 20:34:21 +00007253 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00007254 tcg_temp_free_i32(tmp);
bellard2c0262a2003-09-30 20:34:21 +00007255 break;
7256 case 0x0c:
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007257 tcg_gen_or_i32(tmp, tmp, tmp2);
7258 if (logic_cc) {
7259 gen_logic_CC(tmp);
7260 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007261 store_reg_bx(env, s, rd, tmp);
bellard2c0262a2003-09-30 20:34:21 +00007262 break;
7263 case 0x0d:
bellardb5ff1b32005-11-26 10:38:39 +00007264 if (logic_cc && rd == 15) {
7265 /* MOVS r15, ... is used for exception return. */
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007266 if (IS_USER(s)) {
bellardb5ff1b32005-11-26 10:38:39 +00007267 goto illegal_op;
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007268 }
7269 gen_exception_return(s, tmp2);
bellardb5ff1b32005-11-26 10:38:39 +00007270 } else {
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007271 if (logic_cc) {
7272 gen_logic_CC(tmp2);
7273 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007274 store_reg_bx(env, s, rd, tmp2);
bellardb5ff1b32005-11-26 10:38:39 +00007275 }
bellard2c0262a2003-09-30 20:34:21 +00007276 break;
7277 case 0x0e:
Aurelien Jarnof669df22009-10-15 16:45:14 +02007278 tcg_gen_andc_i32(tmp, tmp, tmp2);
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007279 if (logic_cc) {
7280 gen_logic_CC(tmp);
7281 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007282 store_reg_bx(env, s, rd, tmp);
bellard2c0262a2003-09-30 20:34:21 +00007283 break;
7284 default:
7285 case 0x0f:
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007286 tcg_gen_not_i32(tmp2, tmp2);
7287 if (logic_cc) {
7288 gen_logic_CC(tmp2);
7289 }
Juha Riihimäki21aeb342009-05-06 09:16:12 +03007290 store_reg_bx(env, s, rd, tmp2);
bellard2c0262a2003-09-30 20:34:21 +00007291 break;
7292 }
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007293 if (op1 != 0x0f && op1 != 0x0d) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00007294 tcg_temp_free_i32(tmp2);
Juha Riihimäkie9bb4aa2009-05-06 09:15:38 +03007295 }
bellard2c0262a2003-09-30 20:34:21 +00007296 } else {
7297 /* other instructions */
7298 op1 = (insn >> 24) & 0xf;
7299 switch(op1) {
7300 case 0x0:
7301 case 0x1:
bellard99c475a2005-01-31 20:45:13 +00007302 /* multiplies, extra load/stores */
bellard2c0262a2003-09-30 20:34:21 +00007303 sh = (insn >> 5) & 3;
7304 if (sh == 0) {
7305 if (op1 == 0x0) {
7306 rd = (insn >> 16) & 0xf;
7307 rn = (insn >> 12) & 0xf;
7308 rs = (insn >> 8) & 0xf;
7309 rm = (insn) & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00007310 op1 = (insn >> 20) & 0xf;
7311 switch (op1) {
7312 case 0: case 1: case 2: case 3: case 6:
bellard2c0262a2003-09-30 20:34:21 +00007313 /* 32 bit mul */
pbrook5e3f8782008-03-31 03:47:34 +00007314 tmp = load_reg(s, rs);
7315 tmp2 = load_reg(s, rm);
7316 tcg_gen_mul_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007317 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007318 if (insn & (1 << 22)) {
7319 /* Subtract (mls) */
7320 ARCH(6T2);
pbrook5e3f8782008-03-31 03:47:34 +00007321 tmp2 = load_reg(s, rn);
7322 tcg_gen_sub_i32(tmp, tmp2, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007323 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007324 } else if (insn & (1 << 21)) {
7325 /* Add */
pbrook5e3f8782008-03-31 03:47:34 +00007326 tmp2 = load_reg(s, rn);
7327 tcg_gen_add_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007328 tcg_temp_free_i32(tmp2);
bellard2c0262a2003-09-30 20:34:21 +00007329 }
ths5fafdf22007-09-16 21:08:06 +00007330 if (insn & (1 << 20))
pbrook5e3f8782008-03-31 03:47:34 +00007331 gen_logic_CC(tmp);
7332 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007333 break;
Aurelien Jarno8aac08b2010-12-31 17:50:27 +01007334 case 4:
7335 /* 64 bit mul double accumulate (UMAAL) */
7336 ARCH(6);
pbrook5e3f8782008-03-31 03:47:34 +00007337 tmp = load_reg(s, rs);
7338 tmp2 = load_reg(s, rm);
Aurelien Jarno8aac08b2010-12-31 17:50:27 +01007339 tmp64 = gen_mulu_i64_i32(tmp, tmp2);
7340 gen_addq_lo(s, tmp64, rn);
7341 gen_addq_lo(s, tmp64, rd);
pbrooka7812ae2008-11-17 14:43:54 +00007342 gen_storeq_reg(s, rn, rd, tmp64);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03007343 tcg_temp_free_i64(tmp64);
pbrook9ee6e8b2007-11-11 00:04:49 +00007344 break;
Aurelien Jarno8aac08b2010-12-31 17:50:27 +01007345 case 8: case 9: case 10: case 11:
7346 case 12: case 13: case 14: case 15:
7347 /* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */
7348 tmp = load_reg(s, rs);
7349 tmp2 = load_reg(s, rm);
7350 if (insn & (1 << 22)) {
7351 tmp64 = gen_muls_i64_i32(tmp, tmp2);
7352 } else {
7353 tmp64 = gen_mulu_i64_i32(tmp, tmp2);
7354 }
7355 if (insn & (1 << 21)) { /* mult accumulate */
7356 gen_addq(s, tmp64, rn, rd);
7357 }
7358 if (insn & (1 << 20)) {
7359 gen_logicq_cc(tmp64);
7360 }
7361 gen_storeq_reg(s, rn, rd, tmp64);
7362 tcg_temp_free_i64(tmp64);
7363 break;
7364 default:
7365 goto illegal_op;
bellard2c0262a2003-09-30 20:34:21 +00007366 }
7367 } else {
bellard2c0262a2003-09-30 20:34:21 +00007368 rn = (insn >> 16) & 0xf;
7369 rd = (insn >> 12) & 0xf;
bellard99c475a2005-01-31 20:45:13 +00007370 if (insn & (1 << 23)) {
7371 /* load/store exclusive */
pbrook86753402008-10-22 20:35:54 +00007372 op1 = (insn >> 21) & 0x3;
7373 if (op1)
pbrooka47f43d2008-10-22 21:42:54 +00007374 ARCH(6K);
pbrook86753402008-10-22 20:35:54 +00007375 else
7376 ARCH(6);
Filip Navara3174f8e2009-10-15 13:14:28 +02007377 addr = tcg_temp_local_new_i32();
Aurelien Jarno98a46312009-10-18 15:53:28 +02007378 load_reg_var(s, addr, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00007379 if (insn & (1 << 20)) {
pbrook86753402008-10-22 20:35:54 +00007380 switch (op1) {
7381 case 0: /* ldrex */
Paul Brook426f5ab2009-11-22 21:35:13 +00007382 gen_load_exclusive(s, rd, 15, addr, 2);
pbrook86753402008-10-22 20:35:54 +00007383 break;
7384 case 1: /* ldrexd */
Paul Brook426f5ab2009-11-22 21:35:13 +00007385 gen_load_exclusive(s, rd, rd + 1, addr, 3);
pbrook86753402008-10-22 20:35:54 +00007386 break;
7387 case 2: /* ldrexb */
Paul Brook426f5ab2009-11-22 21:35:13 +00007388 gen_load_exclusive(s, rd, 15, addr, 0);
pbrook86753402008-10-22 20:35:54 +00007389 break;
7390 case 3: /* ldrexh */
Paul Brook426f5ab2009-11-22 21:35:13 +00007391 gen_load_exclusive(s, rd, 15, addr, 1);
pbrook86753402008-10-22 20:35:54 +00007392 break;
7393 default:
7394 abort();
7395 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007396 } else {
7397 rm = insn & 0xf;
pbrook86753402008-10-22 20:35:54 +00007398 switch (op1) {
7399 case 0: /* strex */
Paul Brook426f5ab2009-11-22 21:35:13 +00007400 gen_store_exclusive(s, rd, rm, 15, addr, 2);
pbrook86753402008-10-22 20:35:54 +00007401 break;
7402 case 1: /* strexd */
Aurelien Jarno502e64f2009-12-24 00:18:23 +01007403 gen_store_exclusive(s, rd, rm, rm + 1, addr, 3);
pbrook86753402008-10-22 20:35:54 +00007404 break;
7405 case 2: /* strexb */
Paul Brook426f5ab2009-11-22 21:35:13 +00007406 gen_store_exclusive(s, rd, rm, 15, addr, 0);
pbrook86753402008-10-22 20:35:54 +00007407 break;
7408 case 3: /* strexh */
Paul Brook426f5ab2009-11-22 21:35:13 +00007409 gen_store_exclusive(s, rd, rm, 15, addr, 1);
pbrook86753402008-10-22 20:35:54 +00007410 break;
7411 default:
7412 abort();
7413 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007414 }
Filip Navara3174f8e2009-10-15 13:14:28 +02007415 tcg_temp_free(addr);
bellard2c0262a2003-09-30 20:34:21 +00007416 } else {
bellard99c475a2005-01-31 20:45:13 +00007417 /* SWP instruction */
7418 rm = (insn) & 0xf;
ths3b46e622007-09-17 08:09:54 +00007419
pbrook8984bd22008-03-31 03:47:48 +00007420 /* ??? This is not really atomic. However we know
7421 we never have multiple CPUs running in parallel,
7422 so it is good enough. */
7423 addr = load_reg(s, rn);
7424 tmp = load_reg(s, rm);
bellard99c475a2005-01-31 20:45:13 +00007425 if (insn & (1 << 22)) {
pbrook8984bd22008-03-31 03:47:48 +00007426 tmp2 = gen_ld8u(addr, IS_USER(s));
7427 gen_st8(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00007428 } else {
pbrook8984bd22008-03-31 03:47:48 +00007429 tmp2 = gen_ld32(addr, IS_USER(s));
7430 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00007431 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00007432 tcg_temp_free_i32(addr);
pbrook8984bd22008-03-31 03:47:48 +00007433 store_reg(s, rd, tmp2);
bellard2c0262a2003-09-30 20:34:21 +00007434 }
bellard2c0262a2003-09-30 20:34:21 +00007435 }
7436 } else {
pbrook191f9a92006-06-14 14:36:07 +00007437 int address_offset;
pbrook5fd46862007-03-17 01:43:01 +00007438 int load;
bellard99c475a2005-01-31 20:45:13 +00007439 /* Misc load/store */
bellard2c0262a2003-09-30 20:34:21 +00007440 rn = (insn >> 16) & 0xf;
7441 rd = (insn >> 12) & 0xf;
pbrookb0109802008-03-31 03:47:03 +00007442 addr = load_reg(s, rn);
bellardbeddab72004-05-05 18:36:10 +00007443 if (insn & (1 << 24))
pbrookb0109802008-03-31 03:47:03 +00007444 gen_add_datah_offset(s, insn, 0, addr);
pbrook191f9a92006-06-14 14:36:07 +00007445 address_offset = 0;
bellard2c0262a2003-09-30 20:34:21 +00007446 if (insn & (1 << 20)) {
7447 /* load */
7448 switch(sh) {
7449 case 1:
pbrookb0109802008-03-31 03:47:03 +00007450 tmp = gen_ld16u(addr, IS_USER(s));
bellard2c0262a2003-09-30 20:34:21 +00007451 break;
7452 case 2:
pbrookb0109802008-03-31 03:47:03 +00007453 tmp = gen_ld8s(addr, IS_USER(s));
bellard2c0262a2003-09-30 20:34:21 +00007454 break;
7455 default:
7456 case 3:
pbrookb0109802008-03-31 03:47:03 +00007457 tmp = gen_ld16s(addr, IS_USER(s));
bellard2c0262a2003-09-30 20:34:21 +00007458 break;
7459 }
pbrook5fd46862007-03-17 01:43:01 +00007460 load = 1;
bellard99c475a2005-01-31 20:45:13 +00007461 } else if (sh & 2) {
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04007462 ARCH(5TE);
bellard99c475a2005-01-31 20:45:13 +00007463 /* doubleword */
7464 if (sh & 1) {
7465 /* store */
pbrookb0109802008-03-31 03:47:03 +00007466 tmp = load_reg(s, rd);
7467 gen_st32(tmp, addr, IS_USER(s));
7468 tcg_gen_addi_i32(addr, addr, 4);
7469 tmp = load_reg(s, rd + 1);
7470 gen_st32(tmp, addr, IS_USER(s));
pbrook5fd46862007-03-17 01:43:01 +00007471 load = 0;
bellard99c475a2005-01-31 20:45:13 +00007472 } else {
7473 /* load */
pbrookb0109802008-03-31 03:47:03 +00007474 tmp = gen_ld32(addr, IS_USER(s));
7475 store_reg(s, rd, tmp);
7476 tcg_gen_addi_i32(addr, addr, 4);
7477 tmp = gen_ld32(addr, IS_USER(s));
pbrook5fd46862007-03-17 01:43:01 +00007478 rd++;
7479 load = 1;
bellard99c475a2005-01-31 20:45:13 +00007480 }
pbrook191f9a92006-06-14 14:36:07 +00007481 address_offset = -4;
bellard2c0262a2003-09-30 20:34:21 +00007482 } else {
7483 /* store */
pbrookb0109802008-03-31 03:47:03 +00007484 tmp = load_reg(s, rd);
7485 gen_st16(tmp, addr, IS_USER(s));
pbrook5fd46862007-03-17 01:43:01 +00007486 load = 0;
bellard2c0262a2003-09-30 20:34:21 +00007487 }
pbrook5fd46862007-03-17 01:43:01 +00007488 /* Perform base writeback before the loaded value to
7489 ensure correct behavior with overlapping index registers.
7490 ldrd with base writeback is is undefined if the
7491 destination and index registers overlap. */
bellard2c0262a2003-09-30 20:34:21 +00007492 if (!(insn & (1 << 24))) {
pbrookb0109802008-03-31 03:47:03 +00007493 gen_add_datah_offset(s, insn, address_offset, addr);
7494 store_reg(s, rn, addr);
bellard2c0262a2003-09-30 20:34:21 +00007495 } else if (insn & (1 << 21)) {
pbrook191f9a92006-06-14 14:36:07 +00007496 if (address_offset)
pbrookb0109802008-03-31 03:47:03 +00007497 tcg_gen_addi_i32(addr, addr, address_offset);
7498 store_reg(s, rn, addr);
7499 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00007500 tcg_temp_free_i32(addr);
bellard2c0262a2003-09-30 20:34:21 +00007501 }
pbrook5fd46862007-03-17 01:43:01 +00007502 if (load) {
7503 /* Complete the load. */
pbrookb0109802008-03-31 03:47:03 +00007504 store_reg(s, rd, tmp);
pbrook5fd46862007-03-17 01:43:01 +00007505 }
bellard2c0262a2003-09-30 20:34:21 +00007506 }
7507 break;
7508 case 0x4:
7509 case 0x5:
pbrook9ee6e8b2007-11-11 00:04:49 +00007510 goto do_ldst;
bellard2c0262a2003-09-30 20:34:21 +00007511 case 0x6:
7512 case 0x7:
pbrook9ee6e8b2007-11-11 00:04:49 +00007513 if (insn & (1 << 4)) {
7514 ARCH(6);
7515 /* Armv6 Media instructions. */
7516 rm = insn & 0xf;
7517 rn = (insn >> 16) & 0xf;
7518 rd = (insn >> 12) & 0xf;
7519 rs = (insn >> 8) & 0xf;
7520 switch ((insn >> 23) & 3) {
7521 case 0: /* Parallel add/subtract. */
7522 op1 = (insn >> 20) & 7;
pbrook6ddbc6e2008-03-31 03:46:33 +00007523 tmp = load_reg(s, rn);
7524 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007525 sh = (insn >> 5) & 7;
7526 if ((op1 & 3) == 0 || sh == 5 || sh == 6)
7527 goto illegal_op;
pbrook6ddbc6e2008-03-31 03:46:33 +00007528 gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007529 tcg_temp_free_i32(tmp2);
pbrook6ddbc6e2008-03-31 03:46:33 +00007530 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007531 break;
7532 case 1:
7533 if ((insn & 0x00700020) == 0) {
balrog6c956762008-04-13 00:57:49 +00007534 /* Halfword pack. */
pbrook36706692008-03-31 03:46:19 +00007535 tmp = load_reg(s, rn);
7536 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007537 shift = (insn >> 7) & 0x1f;
pbrook36706692008-03-31 03:46:19 +00007538 if (insn & (1 << 6)) {
7539 /* pkhtb */
balrog22478e72008-07-19 10:12:22 +00007540 if (shift == 0)
7541 shift = 31;
7542 tcg_gen_sari_i32(tmp2, tmp2, shift);
pbrook36706692008-03-31 03:46:19 +00007543 tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
pbrook86831432008-05-11 12:22:01 +00007544 tcg_gen_ext16u_i32(tmp2, tmp2);
pbrook36706692008-03-31 03:46:19 +00007545 } else {
7546 /* pkhbt */
balrog22478e72008-07-19 10:12:22 +00007547 if (shift)
7548 tcg_gen_shli_i32(tmp2, tmp2, shift);
pbrook86831432008-05-11 12:22:01 +00007549 tcg_gen_ext16u_i32(tmp, tmp);
pbrook36706692008-03-31 03:46:19 +00007550 tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
7551 }
7552 tcg_gen_or_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007553 tcg_temp_free_i32(tmp2);
pbrook36706692008-03-31 03:46:19 +00007554 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007555 } else if ((insn & 0x00200020) == 0x00200000) {
7556 /* [us]sat */
pbrook6ddbc6e2008-03-31 03:46:33 +00007557 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007558 shift = (insn >> 7) & 0x1f;
7559 if (insn & (1 << 6)) {
7560 if (shift == 0)
7561 shift = 31;
pbrook6ddbc6e2008-03-31 03:46:33 +00007562 tcg_gen_sari_i32(tmp, tmp, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00007563 } else {
pbrook6ddbc6e2008-03-31 03:46:33 +00007564 tcg_gen_shli_i32(tmp, tmp, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00007565 }
7566 sh = (insn >> 16) & 0x1f;
Christophe Lyon40d3c432011-01-19 17:10:52 +01007567 tmp2 = tcg_const_i32(sh);
7568 if (insn & (1 << 22))
7569 gen_helper_usat(tmp, tmp, tmp2);
7570 else
7571 gen_helper_ssat(tmp, tmp, tmp2);
7572 tcg_temp_free_i32(tmp2);
pbrook6ddbc6e2008-03-31 03:46:33 +00007573 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007574 } else if ((insn & 0x00300fe0) == 0x00200f20) {
7575 /* [us]sat16 */
pbrook6ddbc6e2008-03-31 03:46:33 +00007576 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007577 sh = (insn >> 16) & 0x1f;
Christophe Lyon40d3c432011-01-19 17:10:52 +01007578 tmp2 = tcg_const_i32(sh);
7579 if (insn & (1 << 22))
7580 gen_helper_usat16(tmp, tmp, tmp2);
7581 else
7582 gen_helper_ssat16(tmp, tmp, tmp2);
7583 tcg_temp_free_i32(tmp2);
pbrook6ddbc6e2008-03-31 03:46:33 +00007584 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007585 } else if ((insn & 0x00700fe0) == 0x00000fa0) {
7586 /* Select bytes. */
pbrook6ddbc6e2008-03-31 03:46:33 +00007587 tmp = load_reg(s, rn);
7588 tmp2 = load_reg(s, rm);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007589 tmp3 = tcg_temp_new_i32();
pbrook6ddbc6e2008-03-31 03:46:33 +00007590 tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
7591 gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007592 tcg_temp_free_i32(tmp3);
7593 tcg_temp_free_i32(tmp2);
pbrook6ddbc6e2008-03-31 03:46:33 +00007594 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007595 } else if ((insn & 0x000003e0) == 0x00000060) {
pbrook5e3f8782008-03-31 03:47:34 +00007596 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007597 shift = (insn >> 10) & 3;
Stefan Weil1301f322011-04-28 17:20:37 +02007598 /* ??? In many cases it's not necessary to do a
pbrook9ee6e8b2007-11-11 00:04:49 +00007599 rotate, a shift is sufficient. */
7600 if (shift != 0)
Aurelien Jarnof669df22009-10-15 16:45:14 +02007601 tcg_gen_rotri_i32(tmp, tmp, shift * 8);
pbrook9ee6e8b2007-11-11 00:04:49 +00007602 op1 = (insn >> 20) & 7;
7603 switch (op1) {
pbrook5e3f8782008-03-31 03:47:34 +00007604 case 0: gen_sxtb16(tmp); break;
7605 case 2: gen_sxtb(tmp); break;
7606 case 3: gen_sxth(tmp); break;
7607 case 4: gen_uxtb16(tmp); break;
7608 case 6: gen_uxtb(tmp); break;
7609 case 7: gen_uxth(tmp); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00007610 default: goto illegal_op;
7611 }
7612 if (rn != 15) {
pbrook5e3f8782008-03-31 03:47:34 +00007613 tmp2 = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00007614 if ((op1 & 3) == 0) {
pbrook5e3f8782008-03-31 03:47:34 +00007615 gen_add16(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007616 } else {
pbrook5e3f8782008-03-31 03:47:34 +00007617 tcg_gen_add_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007618 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007619 }
7620 }
balrog6c956762008-04-13 00:57:49 +00007621 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007622 } else if ((insn & 0x003f0f60) == 0x003f0f20) {
7623 /* rev */
pbrookb0109802008-03-31 03:47:03 +00007624 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007625 if (insn & (1 << 22)) {
7626 if (insn & (1 << 7)) {
pbrookb0109802008-03-31 03:47:03 +00007627 gen_revsh(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007628 } else {
7629 ARCH(6T2);
pbrookb0109802008-03-31 03:47:03 +00007630 gen_helper_rbit(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007631 }
7632 } else {
7633 if (insn & (1 << 7))
pbrookb0109802008-03-31 03:47:03 +00007634 gen_rev16(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007635 else
aurel3266896cb2009-03-13 09:34:48 +00007636 tcg_gen_bswap32_i32(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007637 }
pbrookb0109802008-03-31 03:47:03 +00007638 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007639 } else {
7640 goto illegal_op;
7641 }
7642 break;
7643 case 2: /* Multiplies (Type 3). */
Peter Maydell41e95642011-10-19 16:14:05 +00007644 switch ((insn >> 20) & 0x7) {
7645 case 5:
7646 if (((insn >> 6) ^ (insn >> 7)) & 1) {
7647 /* op2 not 00x or 11x : UNDEF */
7648 goto illegal_op;
7649 }
Aurelien Jarno838fa722011-01-06 19:53:56 +01007650 /* Signed multiply most significant [accumulate].
7651 (SMMUL, SMMLA, SMMLS) */
Peter Maydell41e95642011-10-19 16:14:05 +00007652 tmp = load_reg(s, rm);
7653 tmp2 = load_reg(s, rs);
pbrooka7812ae2008-11-17 14:43:54 +00007654 tmp64 = gen_muls_i64_i32(tmp, tmp2);
Aurelien Jarno838fa722011-01-06 19:53:56 +01007655
7656 if (rd != 15) {
7657 tmp = load_reg(s, rd);
7658 if (insn & (1 << 6)) {
7659 tmp64 = gen_subq_msw(tmp64, tmp);
7660 } else {
7661 tmp64 = gen_addq_msw(tmp64, tmp);
7662 }
7663 }
7664 if (insn & (1 << 5)) {
pbrooka7812ae2008-11-17 14:43:54 +00007665 tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
Aurelien Jarno838fa722011-01-06 19:53:56 +01007666 }
pbrooka7812ae2008-11-17 14:43:54 +00007667 tcg_gen_shri_i64(tmp64, tmp64, 32);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007668 tmp = tcg_temp_new_i32();
pbrooka7812ae2008-11-17 14:43:54 +00007669 tcg_gen_trunc_i64_i32(tmp, tmp64);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03007670 tcg_temp_free_i64(tmp64);
balrog955a7dd2008-12-07 14:18:02 +00007671 store_reg(s, rn, tmp);
Peter Maydell41e95642011-10-19 16:14:05 +00007672 break;
7673 case 0:
7674 case 4:
7675 /* SMLAD, SMUAD, SMLSD, SMUSD, SMLALD, SMLSLD */
7676 if (insn & (1 << 7)) {
7677 goto illegal_op;
7678 }
7679 tmp = load_reg(s, rm);
7680 tmp2 = load_reg(s, rs);
pbrook9ee6e8b2007-11-11 00:04:49 +00007681 if (insn & (1 << 5))
pbrook5e3f8782008-03-31 03:47:34 +00007682 gen_swap_half(tmp2);
7683 gen_smul_dual(tmp, tmp2);
pbrook5e3f8782008-03-31 03:47:34 +00007684 if (insn & (1 << 6)) {
Peter Maydelle1d177b2011-03-11 10:09:58 +00007685 /* This subtraction cannot overflow. */
pbrook5e3f8782008-03-31 03:47:34 +00007686 tcg_gen_sub_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007687 } else {
Peter Maydelle1d177b2011-03-11 10:09:58 +00007688 /* This addition cannot overflow 32 bits;
7689 * however it may overflow considered as a signed
7690 * operation, in which case we must set the Q flag.
7691 */
7692 gen_helper_add_setq(tmp, tmp, tmp2);
pbrook5e3f8782008-03-31 03:47:34 +00007693 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00007694 tcg_temp_free_i32(tmp2);
pbrook5e3f8782008-03-31 03:47:34 +00007695 if (insn & (1 << 22)) {
7696 /* smlald, smlsld */
pbrooka7812ae2008-11-17 14:43:54 +00007697 tmp64 = tcg_temp_new_i64();
7698 tcg_gen_ext_i32_i64(tmp64, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007699 tcg_temp_free_i32(tmp);
pbrooka7812ae2008-11-17 14:43:54 +00007700 gen_addq(s, tmp64, rd, rn);
7701 gen_storeq_reg(s, rd, rn, tmp64);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03007702 tcg_temp_free_i64(tmp64);
pbrook5e3f8782008-03-31 03:47:34 +00007703 } else {
7704 /* smuad, smusd, smlad, smlsd */
balrog22478e72008-07-19 10:12:22 +00007705 if (rd != 15)
pbrook9ee6e8b2007-11-11 00:04:49 +00007706 {
balrog22478e72008-07-19 10:12:22 +00007707 tmp2 = load_reg(s, rd);
pbrook5e3f8782008-03-31 03:47:34 +00007708 gen_helper_add_setq(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007709 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007710 }
balrog22478e72008-07-19 10:12:22 +00007711 store_reg(s, rn, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007712 }
Peter Maydell41e95642011-10-19 16:14:05 +00007713 break;
Peter Maydellb8b8ea02011-10-19 16:14:06 +00007714 case 1:
7715 case 3:
7716 /* SDIV, UDIV */
7717 if (!arm_feature(env, ARM_FEATURE_ARM_DIV)) {
7718 goto illegal_op;
7719 }
7720 if (((insn >> 5) & 7) || (rd != 15)) {
7721 goto illegal_op;
7722 }
7723 tmp = load_reg(s, rm);
7724 tmp2 = load_reg(s, rs);
7725 if (insn & (1 << 21)) {
7726 gen_helper_udiv(tmp, tmp, tmp2);
7727 } else {
7728 gen_helper_sdiv(tmp, tmp, tmp2);
7729 }
7730 tcg_temp_free_i32(tmp2);
7731 store_reg(s, rn, tmp);
7732 break;
Peter Maydell41e95642011-10-19 16:14:05 +00007733 default:
7734 goto illegal_op;
pbrook9ee6e8b2007-11-11 00:04:49 +00007735 }
7736 break;
7737 case 3:
7738 op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
7739 switch (op1) {
7740 case 0: /* Unsigned sum of absolute differences. */
pbrook6ddbc6e2008-03-31 03:46:33 +00007741 ARCH(6);
7742 tmp = load_reg(s, rm);
7743 tmp2 = load_reg(s, rs);
7744 gen_helper_usad8(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007745 tcg_temp_free_i32(tmp2);
balrogded9d292008-12-07 14:03:27 +00007746 if (rd != 15) {
7747 tmp2 = load_reg(s, rd);
pbrook6ddbc6e2008-03-31 03:46:33 +00007748 tcg_gen_add_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007749 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007750 }
balrogded9d292008-12-07 14:03:27 +00007751 store_reg(s, rn, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007752 break;
7753 case 0x20: case 0x24: case 0x28: case 0x2c:
7754 /* Bitfield insert/clear. */
7755 ARCH(6T2);
7756 shift = (insn >> 7) & 0x1f;
7757 i = (insn >> 16) & 0x1f;
7758 i = i + 1 - shift;
7759 if (rm == 15) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00007760 tmp = tcg_temp_new_i32();
pbrook5e3f8782008-03-31 03:47:34 +00007761 tcg_gen_movi_i32(tmp, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00007762 } else {
pbrook5e3f8782008-03-31 03:47:34 +00007763 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007764 }
7765 if (i != 32) {
pbrook5e3f8782008-03-31 03:47:34 +00007766 tmp2 = load_reg(s, rd);
pbrook8f8e3aa2008-03-31 03:48:01 +00007767 gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007768 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007769 }
pbrook5e3f8782008-03-31 03:47:34 +00007770 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007771 break;
7772 case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
7773 case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
balrog4cc633c2008-12-07 13:32:09 +00007774 ARCH(6T2);
pbrook5e3f8782008-03-31 03:47:34 +00007775 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007776 shift = (insn >> 7) & 0x1f;
7777 i = ((insn >> 16) & 0x1f) + 1;
7778 if (shift + i > 32)
7779 goto illegal_op;
7780 if (i < 32) {
7781 if (op1 & 0x20) {
pbrook5e3f8782008-03-31 03:47:34 +00007782 gen_ubfx(tmp, shift, (1u << i) - 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00007783 } else {
pbrook5e3f8782008-03-31 03:47:34 +00007784 gen_sbfx(tmp, shift, i);
pbrook9ee6e8b2007-11-11 00:04:49 +00007785 }
7786 }
pbrook5e3f8782008-03-31 03:47:34 +00007787 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007788 break;
7789 default:
7790 goto illegal_op;
7791 }
7792 break;
7793 }
7794 break;
7795 }
7796 do_ldst:
bellard159f3662006-05-22 23:06:04 +00007797 /* Check for undefined extension instructions
7798 * per the ARM Bible IE:
7799 * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx
7800 */
7801 sh = (0xf << 20) | (0xf << 4);
7802 if (op1 == 0x7 && ((insn & sh) == sh))
7803 {
7804 goto illegal_op;
7805 }
bellard2c0262a2003-09-30 20:34:21 +00007806 /* load/store byte/word */
7807 rn = (insn >> 16) & 0xf;
7808 rd = (insn >> 12) & 0xf;
pbrookb0109802008-03-31 03:47:03 +00007809 tmp2 = load_reg(s, rn);
bellardb5ff1b32005-11-26 10:38:39 +00007810 i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
bellard2c0262a2003-09-30 20:34:21 +00007811 if (insn & (1 << 24))
pbrookb0109802008-03-31 03:47:03 +00007812 gen_add_data_offset(s, insn, tmp2);
bellard2c0262a2003-09-30 20:34:21 +00007813 if (insn & (1 << 20)) {
7814 /* load */
bellardb5ff1b32005-11-26 10:38:39 +00007815 if (insn & (1 << 22)) {
pbrookb0109802008-03-31 03:47:03 +00007816 tmp = gen_ld8u(tmp2, i);
bellardb5ff1b32005-11-26 10:38:39 +00007817 } else {
pbrookb0109802008-03-31 03:47:03 +00007818 tmp = gen_ld32(tmp2, i);
bellardb5ff1b32005-11-26 10:38:39 +00007819 }
bellard2c0262a2003-09-30 20:34:21 +00007820 } else {
7821 /* store */
pbrookb0109802008-03-31 03:47:03 +00007822 tmp = load_reg(s, rd);
bellard2c0262a2003-09-30 20:34:21 +00007823 if (insn & (1 << 22))
pbrookb0109802008-03-31 03:47:03 +00007824 gen_st8(tmp, tmp2, i);
bellard2c0262a2003-09-30 20:34:21 +00007825 else
pbrookb0109802008-03-31 03:47:03 +00007826 gen_st32(tmp, tmp2, i);
bellard2c0262a2003-09-30 20:34:21 +00007827 }
7828 if (!(insn & (1 << 24))) {
pbrookb0109802008-03-31 03:47:03 +00007829 gen_add_data_offset(s, insn, tmp2);
7830 store_reg(s, rn, tmp2);
7831 } else if (insn & (1 << 21)) {
7832 store_reg(s, rn, tmp2);
7833 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00007834 tcg_temp_free_i32(tmp2);
bellard2c0262a2003-09-30 20:34:21 +00007835 }
pbrook5fd46862007-03-17 01:43:01 +00007836 if (insn & (1 << 20)) {
7837 /* Complete the load. */
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04007838 store_reg_from_load(env, s, rd, tmp);
pbrook5fd46862007-03-17 01:43:01 +00007839 }
bellard2c0262a2003-09-30 20:34:21 +00007840 break;
7841 case 0x08:
7842 case 0x09:
7843 {
pbrook191abaa2006-02-04 21:50:36 +00007844 int j, n, user, loaded_base;
pbrookb0109802008-03-31 03:47:03 +00007845 TCGv loaded_var;
bellard2c0262a2003-09-30 20:34:21 +00007846 /* load/store multiple words */
7847 /* XXX: store correct base if write back */
bellardb5ff1b32005-11-26 10:38:39 +00007848 user = 0;
7849 if (insn & (1 << 22)) {
7850 if (IS_USER(s))
7851 goto illegal_op; /* only usable in supervisor mode */
7852
7853 if ((insn & (1 << 15)) == 0)
7854 user = 1;
7855 }
bellard2c0262a2003-09-30 20:34:21 +00007856 rn = (insn >> 16) & 0xf;
pbrookb0109802008-03-31 03:47:03 +00007857 addr = load_reg(s, rn);
ths3b46e622007-09-17 08:09:54 +00007858
bellard2c0262a2003-09-30 20:34:21 +00007859 /* compute total size */
pbrook191abaa2006-02-04 21:50:36 +00007860 loaded_base = 0;
pbrooka50f5b92008-06-29 15:25:29 +00007861 TCGV_UNUSED(loaded_var);
bellard2c0262a2003-09-30 20:34:21 +00007862 n = 0;
7863 for(i=0;i<16;i++) {
7864 if (insn & (1 << i))
7865 n++;
7866 }
7867 /* XXX: test invalid n == 0 case ? */
7868 if (insn & (1 << 23)) {
7869 if (insn & (1 << 24)) {
7870 /* pre increment */
pbrookb0109802008-03-31 03:47:03 +00007871 tcg_gen_addi_i32(addr, addr, 4);
bellard2c0262a2003-09-30 20:34:21 +00007872 } else {
7873 /* post increment */
7874 }
7875 } else {
7876 if (insn & (1 << 24)) {
7877 /* pre decrement */
pbrookb0109802008-03-31 03:47:03 +00007878 tcg_gen_addi_i32(addr, addr, -(n * 4));
bellard2c0262a2003-09-30 20:34:21 +00007879 } else {
7880 /* post decrement */
7881 if (n != 1)
pbrookb0109802008-03-31 03:47:03 +00007882 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
bellard2c0262a2003-09-30 20:34:21 +00007883 }
7884 }
7885 j = 0;
7886 for(i=0;i<16;i++) {
7887 if (insn & (1 << i)) {
7888 if (insn & (1 << 20)) {
7889 /* load */
pbrookb0109802008-03-31 03:47:03 +00007890 tmp = gen_ld32(addr, IS_USER(s));
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04007891 if (user) {
Juha Riihimäkib75263d2009-10-22 15:17:36 +03007892 tmp2 = tcg_const_i32(i);
7893 gen_helper_set_user_reg(tmp2, tmp);
7894 tcg_temp_free_i32(tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007895 tcg_temp_free_i32(tmp);
pbrook191abaa2006-02-04 21:50:36 +00007896 } else if (i == rn) {
pbrookb0109802008-03-31 03:47:03 +00007897 loaded_var = tmp;
pbrook191abaa2006-02-04 21:50:36 +00007898 loaded_base = 1;
bellardb5ff1b32005-11-26 10:38:39 +00007899 } else {
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04007900 store_reg_from_load(env, s, i, tmp);
bellardb5ff1b32005-11-26 10:38:39 +00007901 }
bellard2c0262a2003-09-30 20:34:21 +00007902 } else {
7903 /* store */
7904 if (i == 15) {
balrog7a774c82007-06-10 13:53:18 +00007905 /* special case: r15 = PC + 8 */
7906 val = (long)s->pc + 4;
Peter Maydell7d1b0092011-03-06 21:39:54 +00007907 tmp = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +00007908 tcg_gen_movi_i32(tmp, val);
bellardb5ff1b32005-11-26 10:38:39 +00007909 } else if (user) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00007910 tmp = tcg_temp_new_i32();
Juha Riihimäkib75263d2009-10-22 15:17:36 +03007911 tmp2 = tcg_const_i32(i);
7912 gen_helper_get_user_reg(tmp, tmp2);
7913 tcg_temp_free_i32(tmp2);
bellard2c0262a2003-09-30 20:34:21 +00007914 } else {
pbrookb0109802008-03-31 03:47:03 +00007915 tmp = load_reg(s, i);
bellard2c0262a2003-09-30 20:34:21 +00007916 }
pbrookb0109802008-03-31 03:47:03 +00007917 gen_st32(tmp, addr, IS_USER(s));
bellard2c0262a2003-09-30 20:34:21 +00007918 }
7919 j++;
7920 /* no need to add after the last transfer */
7921 if (j != n)
pbrookb0109802008-03-31 03:47:03 +00007922 tcg_gen_addi_i32(addr, addr, 4);
bellard2c0262a2003-09-30 20:34:21 +00007923 }
7924 }
7925 if (insn & (1 << 21)) {
7926 /* write back */
7927 if (insn & (1 << 23)) {
7928 if (insn & (1 << 24)) {
7929 /* pre increment */
7930 } else {
7931 /* post increment */
pbrookb0109802008-03-31 03:47:03 +00007932 tcg_gen_addi_i32(addr, addr, 4);
bellard2c0262a2003-09-30 20:34:21 +00007933 }
7934 } else {
7935 if (insn & (1 << 24)) {
7936 /* pre decrement */
7937 if (n != 1)
pbrookb0109802008-03-31 03:47:03 +00007938 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
bellard2c0262a2003-09-30 20:34:21 +00007939 } else {
7940 /* post decrement */
pbrookb0109802008-03-31 03:47:03 +00007941 tcg_gen_addi_i32(addr, addr, -(n * 4));
bellard2c0262a2003-09-30 20:34:21 +00007942 }
7943 }
pbrookb0109802008-03-31 03:47:03 +00007944 store_reg(s, rn, addr);
7945 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00007946 tcg_temp_free_i32(addr);
bellard2c0262a2003-09-30 20:34:21 +00007947 }
pbrook191abaa2006-02-04 21:50:36 +00007948 if (loaded_base) {
pbrookb0109802008-03-31 03:47:03 +00007949 store_reg(s, rn, loaded_var);
pbrook191abaa2006-02-04 21:50:36 +00007950 }
bellardb5ff1b32005-11-26 10:38:39 +00007951 if ((insn & (1 << 22)) && !user) {
7952 /* Restore CPSR from SPSR. */
pbrookd9ba4832008-03-31 03:46:50 +00007953 tmp = load_cpu_field(spsr);
7954 gen_set_cpsr(tmp, 0xffffffff);
Peter Maydell7d1b0092011-03-06 21:39:54 +00007955 tcg_temp_free_i32(tmp);
bellardb5ff1b32005-11-26 10:38:39 +00007956 s->is_jmp = DISAS_UPDATE;
7957 }
bellard2c0262a2003-09-30 20:34:21 +00007958 }
7959 break;
7960 case 0xa:
7961 case 0xb:
7962 {
bellard99c475a2005-01-31 20:45:13 +00007963 int32_t offset;
ths3b46e622007-09-17 08:09:54 +00007964
bellard2c0262a2003-09-30 20:34:21 +00007965 /* branch (and link) */
bellard99c475a2005-01-31 20:45:13 +00007966 val = (int32_t)s->pc;
bellard2c0262a2003-09-30 20:34:21 +00007967 if (insn & (1 << 24)) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00007968 tmp = tcg_temp_new_i32();
pbrook5e3f8782008-03-31 03:47:34 +00007969 tcg_gen_movi_i32(tmp, val);
7970 store_reg(s, 14, tmp);
bellard2c0262a2003-09-30 20:34:21 +00007971 }
bellard99c475a2005-01-31 20:45:13 +00007972 offset = (((int32_t)insn << 8) >> 8);
bellard2c0262a2003-09-30 20:34:21 +00007973 val += (offset << 2) + 4;
bellard8aaca4c2005-04-23 18:27:52 +00007974 gen_jmp(s, val);
bellard2c0262a2003-09-30 20:34:21 +00007975 }
7976 break;
bellardb7bcbe92005-02-22 19:27:29 +00007977 case 0xc:
7978 case 0xd:
7979 case 0xe:
7980 /* Coprocessor. */
pbrook9ee6e8b2007-11-11 00:04:49 +00007981 if (disas_coproc_insn(env, s, insn))
balrogc1713132007-04-30 01:26:42 +00007982 goto illegal_op;
bellardb7bcbe92005-02-22 19:27:29 +00007983 break;
bellard2c0262a2003-09-30 20:34:21 +00007984 case 0xf:
7985 /* swi */
pbrook5e3f8782008-03-31 03:47:34 +00007986 gen_set_pc_im(s->pc);
pbrook9ee6e8b2007-11-11 00:04:49 +00007987 s->is_jmp = DISAS_SWI;
bellard2c0262a2003-09-30 20:34:21 +00007988 break;
bellard2c0262a2003-09-30 20:34:21 +00007989 default:
7990 illegal_op:
Peter Maydellbc4a0de2011-01-14 20:39:19 +01007991 gen_exception_insn(s, 4, EXCP_UDEF);
bellard2c0262a2003-09-30 20:34:21 +00007992 break;
7993 }
7994 }
7995}
7996
pbrook9ee6e8b2007-11-11 00:04:49 +00007997/* Return true if this is a Thumb-2 logical op. */
7998static int
7999thumb2_logic_op(int op)
8000{
8001 return (op < 8);
8002}
8003
8004/* Generate code for a Thumb-2 data processing operation. If CONDS is nonzero
8005 then set condition code flags based on the result of the operation.
8006 If SHIFTER_OUT is nonzero then set the carry flag for logical operations
8007 to the high bit of T1.
8008 Returns zero if the opcode is valid. */
8009
8010static int
Filip Navara396e4672009-10-15 12:55:34 +02008011gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCGv t0, TCGv t1)
pbrook9ee6e8b2007-11-11 00:04:49 +00008012{
8013 int logic_cc;
8014
8015 logic_cc = 0;
8016 switch (op) {
8017 case 0: /* and */
Filip Navara396e4672009-10-15 12:55:34 +02008018 tcg_gen_and_i32(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008019 logic_cc = conds;
8020 break;
8021 case 1: /* bic */
Aurelien Jarnof669df22009-10-15 16:45:14 +02008022 tcg_gen_andc_i32(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008023 logic_cc = conds;
8024 break;
8025 case 2: /* orr */
Filip Navara396e4672009-10-15 12:55:34 +02008026 tcg_gen_or_i32(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008027 logic_cc = conds;
8028 break;
8029 case 3: /* orn */
Peter Maydell29501f12011-03-06 20:32:09 +00008030 tcg_gen_orc_i32(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008031 logic_cc = conds;
8032 break;
8033 case 4: /* eor */
Filip Navara396e4672009-10-15 12:55:34 +02008034 tcg_gen_xor_i32(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008035 logic_cc = conds;
8036 break;
8037 case 8: /* add */
8038 if (conds)
Filip Navara396e4672009-10-15 12:55:34 +02008039 gen_helper_add_cc(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008040 else
Filip Navara396e4672009-10-15 12:55:34 +02008041 tcg_gen_add_i32(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008042 break;
8043 case 10: /* adc */
8044 if (conds)
Filip Navara396e4672009-10-15 12:55:34 +02008045 gen_helper_adc_cc(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008046 else
Filip Navara396e4672009-10-15 12:55:34 +02008047 gen_adc(t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008048 break;
8049 case 11: /* sbc */
8050 if (conds)
Filip Navara396e4672009-10-15 12:55:34 +02008051 gen_helper_sbc_cc(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008052 else
Filip Navara396e4672009-10-15 12:55:34 +02008053 gen_sub_carry(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008054 break;
8055 case 13: /* sub */
8056 if (conds)
Filip Navara396e4672009-10-15 12:55:34 +02008057 gen_helper_sub_cc(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008058 else
Filip Navara396e4672009-10-15 12:55:34 +02008059 tcg_gen_sub_i32(t0, t0, t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008060 break;
8061 case 14: /* rsb */
8062 if (conds)
Filip Navara396e4672009-10-15 12:55:34 +02008063 gen_helper_sub_cc(t0, t1, t0);
pbrook9ee6e8b2007-11-11 00:04:49 +00008064 else
Filip Navara396e4672009-10-15 12:55:34 +02008065 tcg_gen_sub_i32(t0, t1, t0);
pbrook9ee6e8b2007-11-11 00:04:49 +00008066 break;
8067 default: /* 5, 6, 7, 9, 12, 15. */
8068 return 1;
8069 }
8070 if (logic_cc) {
Filip Navara396e4672009-10-15 12:55:34 +02008071 gen_logic_CC(t0);
pbrook9ee6e8b2007-11-11 00:04:49 +00008072 if (shifter_out)
Filip Navara396e4672009-10-15 12:55:34 +02008073 gen_set_CF_bit31(t1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008074 }
8075 return 0;
8076}
8077
8078/* Translate a 32-bit thumb instruction. Returns nonzero if the instruction
8079 is not legal. */
8080static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
8081{
pbrookb0109802008-03-31 03:47:03 +00008082 uint32_t insn, imm, shift, offset;
pbrook9ee6e8b2007-11-11 00:04:49 +00008083 uint32_t rd, rn, rm, rs;
pbrookb26eefb2008-03-31 03:44:26 +00008084 TCGv tmp;
pbrook6ddbc6e2008-03-31 03:46:33 +00008085 TCGv tmp2;
8086 TCGv tmp3;
pbrookb0109802008-03-31 03:47:03 +00008087 TCGv addr;
pbrooka7812ae2008-11-17 14:43:54 +00008088 TCGv_i64 tmp64;
pbrook9ee6e8b2007-11-11 00:04:49 +00008089 int op;
8090 int shiftop;
8091 int conds;
8092 int logic_cc;
8093
8094 if (!(arm_feature(env, ARM_FEATURE_THUMB2)
8095 || arm_feature (env, ARM_FEATURE_M))) {
balrog601d70b2008-04-20 01:03:45 +00008096 /* Thumb-1 cores may need to treat bl and blx as a pair of
pbrook9ee6e8b2007-11-11 00:04:49 +00008097 16-bit instructions to get correct prefetch abort behavior. */
8098 insn = insn_hw1;
8099 if ((insn & (1 << 12)) == 0) {
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04008100 ARCH(5);
pbrook9ee6e8b2007-11-11 00:04:49 +00008101 /* Second half of blx. */
8102 offset = ((insn & 0x7ff) << 1);
pbrookd9ba4832008-03-31 03:46:50 +00008103 tmp = load_reg(s, 14);
8104 tcg_gen_addi_i32(tmp, tmp, offset);
8105 tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
pbrook9ee6e8b2007-11-11 00:04:49 +00008106
Peter Maydell7d1b0092011-03-06 21:39:54 +00008107 tmp2 = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +00008108 tcg_gen_movi_i32(tmp2, s->pc | 1);
pbrookd9ba4832008-03-31 03:46:50 +00008109 store_reg(s, 14, tmp2);
8110 gen_bx(s, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008111 return 0;
8112 }
8113 if (insn & (1 << 11)) {
8114 /* Second half of bl. */
8115 offset = ((insn & 0x7ff) << 1) | 1;
pbrookd9ba4832008-03-31 03:46:50 +00008116 tmp = load_reg(s, 14);
balrog6a0d8a12008-04-13 13:25:31 +00008117 tcg_gen_addi_i32(tmp, tmp, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00008118
Peter Maydell7d1b0092011-03-06 21:39:54 +00008119 tmp2 = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +00008120 tcg_gen_movi_i32(tmp2, s->pc | 1);
pbrookd9ba4832008-03-31 03:46:50 +00008121 store_reg(s, 14, tmp2);
8122 gen_bx(s, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008123 return 0;
8124 }
8125 if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
8126 /* Instruction spans a page boundary. Implement it as two
8127 16-bit instructions in case the second half causes an
8128 prefetch abort. */
8129 offset = ((int32_t)insn << 21) >> 9;
Filip Navara396e4672009-10-15 12:55:34 +02008130 tcg_gen_movi_i32(cpu_R[14], s->pc + 2 + offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00008131 return 0;
8132 }
8133 /* Fall through to 32-bit decode. */
8134 }
8135
8136 insn = lduw_code(s->pc);
8137 s->pc += 2;
8138 insn |= (uint32_t)insn_hw1 << 16;
8139
8140 if ((insn & 0xf800e800) != 0xf000e800) {
8141 ARCH(6T2);
8142 }
8143
8144 rn = (insn >> 16) & 0xf;
8145 rs = (insn >> 12) & 0xf;
8146 rd = (insn >> 8) & 0xf;
8147 rm = insn & 0xf;
8148 switch ((insn >> 25) & 0xf) {
8149 case 0: case 1: case 2: case 3:
8150 /* 16-bit instructions. Should never happen. */
8151 abort();
8152 case 4:
8153 if (insn & (1 << 22)) {
8154 /* Other load/store, table branch. */
8155 if (insn & 0x01200000) {
8156 /* Load/store doubleword. */
8157 if (rn == 15) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008158 addr = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +00008159 tcg_gen_movi_i32(addr, s->pc & ~3);
pbrook9ee6e8b2007-11-11 00:04:49 +00008160 } else {
pbrookb0109802008-03-31 03:47:03 +00008161 addr = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00008162 }
8163 offset = (insn & 0xff) * 4;
8164 if ((insn & (1 << 23)) == 0)
8165 offset = -offset;
8166 if (insn & (1 << 24)) {
pbrookb0109802008-03-31 03:47:03 +00008167 tcg_gen_addi_i32(addr, addr, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00008168 offset = 0;
8169 }
8170 if (insn & (1 << 20)) {
8171 /* ldrd */
pbrookb0109802008-03-31 03:47:03 +00008172 tmp = gen_ld32(addr, IS_USER(s));
8173 store_reg(s, rs, tmp);
8174 tcg_gen_addi_i32(addr, addr, 4);
8175 tmp = gen_ld32(addr, IS_USER(s));
8176 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008177 } else {
8178 /* strd */
pbrookb0109802008-03-31 03:47:03 +00008179 tmp = load_reg(s, rs);
8180 gen_st32(tmp, addr, IS_USER(s));
8181 tcg_gen_addi_i32(addr, addr, 4);
8182 tmp = load_reg(s, rd);
8183 gen_st32(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00008184 }
8185 if (insn & (1 << 21)) {
8186 /* Base writeback. */
8187 if (rn == 15)
8188 goto illegal_op;
pbrookb0109802008-03-31 03:47:03 +00008189 tcg_gen_addi_i32(addr, addr, offset - 4);
8190 store_reg(s, rn, addr);
8191 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008192 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00008193 }
8194 } else if ((insn & (1 << 23)) == 0) {
8195 /* Load/store exclusive word. */
Filip Navara3174f8e2009-10-15 13:14:28 +02008196 addr = tcg_temp_local_new();
Aurelien Jarno98a46312009-10-18 15:53:28 +02008197 load_reg_var(s, addr, rn);
Paul Brook426f5ab2009-11-22 21:35:13 +00008198 tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008199 if (insn & (1 << 20)) {
Paul Brook426f5ab2009-11-22 21:35:13 +00008200 gen_load_exclusive(s, rs, 15, addr, 2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008201 } else {
Paul Brook426f5ab2009-11-22 21:35:13 +00008202 gen_store_exclusive(s, rd, rs, 15, addr, 2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008203 }
Filip Navara3174f8e2009-10-15 13:14:28 +02008204 tcg_temp_free(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00008205 } else if ((insn & (1 << 6)) == 0) {
8206 /* Table Branch. */
8207 if (rn == 15) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008208 addr = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +00008209 tcg_gen_movi_i32(addr, s->pc);
pbrook9ee6e8b2007-11-11 00:04:49 +00008210 } else {
pbrookb0109802008-03-31 03:47:03 +00008211 addr = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00008212 }
pbrookb26eefb2008-03-31 03:44:26 +00008213 tmp = load_reg(s, rm);
pbrookb0109802008-03-31 03:47:03 +00008214 tcg_gen_add_i32(addr, addr, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008215 if (insn & (1 << 4)) {
8216 /* tbh */
pbrookb0109802008-03-31 03:47:03 +00008217 tcg_gen_add_i32(addr, addr, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008218 tcg_temp_free_i32(tmp);
pbrookb0109802008-03-31 03:47:03 +00008219 tmp = gen_ld16u(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00008220 } else { /* tbb */
Peter Maydell7d1b0092011-03-06 21:39:54 +00008221 tcg_temp_free_i32(tmp);
pbrookb0109802008-03-31 03:47:03 +00008222 tmp = gen_ld8u(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00008223 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00008224 tcg_temp_free_i32(addr);
pbrookb0109802008-03-31 03:47:03 +00008225 tcg_gen_shli_i32(tmp, tmp, 1);
8226 tcg_gen_addi_i32(tmp, tmp, s->pc);
8227 store_reg(s, 15, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008228 } else {
8229 /* Load/store exclusive byte/halfword/doubleword. */
Paul Brook426f5ab2009-11-22 21:35:13 +00008230 ARCH(7);
pbrook9ee6e8b2007-11-11 00:04:49 +00008231 op = (insn >> 4) & 0x3;
Paul Brook426f5ab2009-11-22 21:35:13 +00008232 if (op == 2) {
8233 goto illegal_op;
8234 }
Filip Navara3174f8e2009-10-15 13:14:28 +02008235 addr = tcg_temp_local_new();
Aurelien Jarno98a46312009-10-18 15:53:28 +02008236 load_reg_var(s, addr, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00008237 if (insn & (1 << 20)) {
Paul Brook426f5ab2009-11-22 21:35:13 +00008238 gen_load_exclusive(s, rs, rd, addr, op);
pbrook9ee6e8b2007-11-11 00:04:49 +00008239 } else {
Paul Brook426f5ab2009-11-22 21:35:13 +00008240 gen_store_exclusive(s, rm, rs, rd, addr, op);
pbrook9ee6e8b2007-11-11 00:04:49 +00008241 }
Filip Navara3174f8e2009-10-15 13:14:28 +02008242 tcg_temp_free(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00008243 }
8244 } else {
8245 /* Load/store multiple, RFE, SRS. */
8246 if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
8247 /* Not available in user mode. */
pbrookb0109802008-03-31 03:47:03 +00008248 if (IS_USER(s))
pbrook9ee6e8b2007-11-11 00:04:49 +00008249 goto illegal_op;
8250 if (insn & (1 << 20)) {
8251 /* rfe */
pbrookb0109802008-03-31 03:47:03 +00008252 addr = load_reg(s, rn);
8253 if ((insn & (1 << 24)) == 0)
8254 tcg_gen_addi_i32(addr, addr, -8);
8255 /* Load PC into tmp and CPSR into tmp2. */
8256 tmp = gen_ld32(addr, 0);
8257 tcg_gen_addi_i32(addr, addr, 4);
8258 tmp2 = gen_ld32(addr, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00008259 if (insn & (1 << 21)) {
8260 /* Base writeback. */
pbrookb0109802008-03-31 03:47:03 +00008261 if (insn & (1 << 24)) {
8262 tcg_gen_addi_i32(addr, addr, 4);
8263 } else {
8264 tcg_gen_addi_i32(addr, addr, -4);
8265 }
8266 store_reg(s, rn, addr);
8267 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008268 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00008269 }
pbrookb0109802008-03-31 03:47:03 +00008270 gen_rfe(s, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008271 } else {
8272 /* srs */
8273 op = (insn & 0x1f);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008274 addr = tcg_temp_new_i32();
Peter Maydell39ea3d42011-01-14 20:39:18 +01008275 tmp = tcg_const_i32(op);
8276 gen_helper_get_r13_banked(addr, cpu_env, tmp);
8277 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008278 if ((insn & (1 << 24)) == 0) {
pbrookb0109802008-03-31 03:47:03 +00008279 tcg_gen_addi_i32(addr, addr, -8);
pbrook9ee6e8b2007-11-11 00:04:49 +00008280 }
pbrookb0109802008-03-31 03:47:03 +00008281 tmp = load_reg(s, 14);
8282 gen_st32(tmp, addr, 0);
8283 tcg_gen_addi_i32(addr, addr, 4);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008284 tmp = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +00008285 gen_helper_cpsr_read(tmp);
8286 gen_st32(tmp, addr, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00008287 if (insn & (1 << 21)) {
8288 if ((insn & (1 << 24)) == 0) {
pbrookb0109802008-03-31 03:47:03 +00008289 tcg_gen_addi_i32(addr, addr, -4);
pbrook9ee6e8b2007-11-11 00:04:49 +00008290 } else {
pbrookb0109802008-03-31 03:47:03 +00008291 tcg_gen_addi_i32(addr, addr, 4);
pbrook9ee6e8b2007-11-11 00:04:49 +00008292 }
Peter Maydell39ea3d42011-01-14 20:39:18 +01008293 tmp = tcg_const_i32(op);
8294 gen_helper_set_r13_banked(cpu_env, tmp, addr);
8295 tcg_temp_free_i32(tmp);
pbrookb0109802008-03-31 03:47:03 +00008296 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008297 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00008298 }
8299 }
8300 } else {
YuYeon Oh5856d442011-04-25 01:23:58 +00008301 int i, loaded_base = 0;
8302 TCGv loaded_var;
pbrook9ee6e8b2007-11-11 00:04:49 +00008303 /* Load/store multiple. */
pbrookb0109802008-03-31 03:47:03 +00008304 addr = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00008305 offset = 0;
8306 for (i = 0; i < 16; i++) {
8307 if (insn & (1 << i))
8308 offset += 4;
8309 }
8310 if (insn & (1 << 24)) {
pbrookb0109802008-03-31 03:47:03 +00008311 tcg_gen_addi_i32(addr, addr, -offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00008312 }
8313
YuYeon Oh5856d442011-04-25 01:23:58 +00008314 TCGV_UNUSED(loaded_var);
pbrook9ee6e8b2007-11-11 00:04:49 +00008315 for (i = 0; i < 16; i++) {
8316 if ((insn & (1 << i)) == 0)
8317 continue;
8318 if (insn & (1 << 20)) {
8319 /* Load. */
pbrookb0109802008-03-31 03:47:03 +00008320 tmp = gen_ld32(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00008321 if (i == 15) {
pbrookb0109802008-03-31 03:47:03 +00008322 gen_bx(s, tmp);
YuYeon Oh5856d442011-04-25 01:23:58 +00008323 } else if (i == rn) {
8324 loaded_var = tmp;
8325 loaded_base = 1;
pbrook9ee6e8b2007-11-11 00:04:49 +00008326 } else {
pbrookb0109802008-03-31 03:47:03 +00008327 store_reg(s, i, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008328 }
8329 } else {
8330 /* Store. */
pbrookb0109802008-03-31 03:47:03 +00008331 tmp = load_reg(s, i);
8332 gen_st32(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00008333 }
pbrookb0109802008-03-31 03:47:03 +00008334 tcg_gen_addi_i32(addr, addr, 4);
pbrook9ee6e8b2007-11-11 00:04:49 +00008335 }
YuYeon Oh5856d442011-04-25 01:23:58 +00008336 if (loaded_base) {
8337 store_reg(s, rn, loaded_var);
8338 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008339 if (insn & (1 << 21)) {
8340 /* Base register writeback. */
8341 if (insn & (1 << 24)) {
pbrookb0109802008-03-31 03:47:03 +00008342 tcg_gen_addi_i32(addr, addr, -offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00008343 }
8344 /* Fault if writeback register is in register list. */
8345 if (insn & (1 << rn))
8346 goto illegal_op;
pbrookb0109802008-03-31 03:47:03 +00008347 store_reg(s, rn, addr);
8348 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008349 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00008350 }
8351 }
8352 }
8353 break;
Johan Bengtsson2af9ab72010-12-07 12:01:44 +00008354 case 5:
8355
pbrook9ee6e8b2007-11-11 00:04:49 +00008356 op = (insn >> 21) & 0xf;
Johan Bengtsson2af9ab72010-12-07 12:01:44 +00008357 if (op == 6) {
8358 /* Halfword pack. */
8359 tmp = load_reg(s, rn);
8360 tmp2 = load_reg(s, rm);
8361 shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3);
8362 if (insn & (1 << 5)) {
8363 /* pkhtb */
8364 if (shift == 0)
8365 shift = 31;
8366 tcg_gen_sari_i32(tmp2, tmp2, shift);
8367 tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
8368 tcg_gen_ext16u_i32(tmp2, tmp2);
8369 } else {
8370 /* pkhbt */
8371 if (shift)
8372 tcg_gen_shli_i32(tmp2, tmp2, shift);
8373 tcg_gen_ext16u_i32(tmp, tmp);
8374 tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
8375 }
8376 tcg_gen_or_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008377 tcg_temp_free_i32(tmp2);
Filip Navara3174f8e2009-10-15 13:14:28 +02008378 store_reg(s, rd, tmp);
8379 } else {
Johan Bengtsson2af9ab72010-12-07 12:01:44 +00008380 /* Data processing register constant shift. */
8381 if (rn == 15) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008382 tmp = tcg_temp_new_i32();
Johan Bengtsson2af9ab72010-12-07 12:01:44 +00008383 tcg_gen_movi_i32(tmp, 0);
8384 } else {
8385 tmp = load_reg(s, rn);
8386 }
8387 tmp2 = load_reg(s, rm);
8388
8389 shiftop = (insn >> 4) & 3;
8390 shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
8391 conds = (insn & (1 << 20)) != 0;
8392 logic_cc = (conds && thumb2_logic_op(op));
8393 gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
8394 if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
8395 goto illegal_op;
Peter Maydell7d1b0092011-03-06 21:39:54 +00008396 tcg_temp_free_i32(tmp2);
Johan Bengtsson2af9ab72010-12-07 12:01:44 +00008397 if (rd != 15) {
8398 store_reg(s, rd, tmp);
8399 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008400 tcg_temp_free_i32(tmp);
Johan Bengtsson2af9ab72010-12-07 12:01:44 +00008401 }
Filip Navara3174f8e2009-10-15 13:14:28 +02008402 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008403 break;
8404 case 13: /* Misc data processing. */
8405 op = ((insn >> 22) & 6) | ((insn >> 7) & 1);
8406 if (op < 4 && (insn & 0xf000) != 0xf000)
8407 goto illegal_op;
8408 switch (op) {
8409 case 0: /* Register controlled shift. */
pbrook8984bd22008-03-31 03:47:48 +00008410 tmp = load_reg(s, rn);
8411 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008412 if ((insn & 0x70) != 0)
8413 goto illegal_op;
8414 op = (insn >> 21) & 3;
pbrook8984bd22008-03-31 03:47:48 +00008415 logic_cc = (insn & (1 << 20)) != 0;
8416 gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
8417 if (logic_cc)
8418 gen_logic_CC(tmp);
Juha Riihimäki21aeb342009-05-06 09:16:12 +03008419 store_reg_bx(env, s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008420 break;
8421 case 1: /* Sign/zero extend. */
pbrook5e3f8782008-03-31 03:47:34 +00008422 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008423 shift = (insn >> 4) & 3;
Stefan Weil1301f322011-04-28 17:20:37 +02008424 /* ??? In many cases it's not necessary to do a
pbrook9ee6e8b2007-11-11 00:04:49 +00008425 rotate, a shift is sufficient. */
8426 if (shift != 0)
Aurelien Jarnof669df22009-10-15 16:45:14 +02008427 tcg_gen_rotri_i32(tmp, tmp, shift * 8);
pbrook9ee6e8b2007-11-11 00:04:49 +00008428 op = (insn >> 20) & 7;
8429 switch (op) {
pbrook5e3f8782008-03-31 03:47:34 +00008430 case 0: gen_sxth(tmp); break;
8431 case 1: gen_uxth(tmp); break;
8432 case 2: gen_sxtb16(tmp); break;
8433 case 3: gen_uxtb16(tmp); break;
8434 case 4: gen_sxtb(tmp); break;
8435 case 5: gen_uxtb(tmp); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00008436 default: goto illegal_op;
8437 }
8438 if (rn != 15) {
pbrook5e3f8782008-03-31 03:47:34 +00008439 tmp2 = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00008440 if ((op >> 1) == 1) {
pbrook5e3f8782008-03-31 03:47:34 +00008441 gen_add16(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008442 } else {
pbrook5e3f8782008-03-31 03:47:34 +00008443 tcg_gen_add_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008444 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008445 }
8446 }
pbrook5e3f8782008-03-31 03:47:34 +00008447 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008448 break;
8449 case 2: /* SIMD add/subtract. */
8450 op = (insn >> 20) & 7;
8451 shift = (insn >> 4) & 7;
8452 if ((op & 3) == 3 || (shift & 3) == 3)
8453 goto illegal_op;
pbrook6ddbc6e2008-03-31 03:46:33 +00008454 tmp = load_reg(s, rn);
8455 tmp2 = load_reg(s, rm);
8456 gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008457 tcg_temp_free_i32(tmp2);
pbrook6ddbc6e2008-03-31 03:46:33 +00008458 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008459 break;
8460 case 3: /* Other data processing. */
8461 op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
8462 if (op < 4) {
8463 /* Saturating add/subtract. */
pbrookd9ba4832008-03-31 03:46:50 +00008464 tmp = load_reg(s, rn);
8465 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008466 if (op & 1)
Johan Bengtsson4809c612010-12-07 12:01:44 +00008467 gen_helper_double_saturate(tmp, tmp);
8468 if (op & 2)
pbrookd9ba4832008-03-31 03:46:50 +00008469 gen_helper_sub_saturate(tmp, tmp2, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008470 else
pbrookd9ba4832008-03-31 03:46:50 +00008471 gen_helper_add_saturate(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008472 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008473 } else {
pbrookd9ba4832008-03-31 03:46:50 +00008474 tmp = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00008475 switch (op) {
8476 case 0x0a: /* rbit */
pbrookd9ba4832008-03-31 03:46:50 +00008477 gen_helper_rbit(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008478 break;
8479 case 0x08: /* rev */
aurel3266896cb2009-03-13 09:34:48 +00008480 tcg_gen_bswap32_i32(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008481 break;
8482 case 0x09: /* rev16 */
pbrookd9ba4832008-03-31 03:46:50 +00008483 gen_rev16(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008484 break;
8485 case 0x0b: /* revsh */
pbrookd9ba4832008-03-31 03:46:50 +00008486 gen_revsh(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008487 break;
8488 case 0x10: /* sel */
pbrookd9ba4832008-03-31 03:46:50 +00008489 tmp2 = load_reg(s, rm);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008490 tmp3 = tcg_temp_new_i32();
pbrook6ddbc6e2008-03-31 03:46:33 +00008491 tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
pbrookd9ba4832008-03-31 03:46:50 +00008492 gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008493 tcg_temp_free_i32(tmp3);
8494 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008495 break;
8496 case 0x18: /* clz */
pbrookd9ba4832008-03-31 03:46:50 +00008497 gen_helper_clz(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008498 break;
8499 default:
8500 goto illegal_op;
8501 }
8502 }
pbrookd9ba4832008-03-31 03:46:50 +00008503 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008504 break;
8505 case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */
8506 op = (insn >> 4) & 0xf;
pbrookd9ba4832008-03-31 03:46:50 +00008507 tmp = load_reg(s, rn);
8508 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008509 switch ((insn >> 20) & 7) {
8510 case 0: /* 32 x 32 -> 32 */
pbrookd9ba4832008-03-31 03:46:50 +00008511 tcg_gen_mul_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008512 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008513 if (rs != 15) {
pbrookd9ba4832008-03-31 03:46:50 +00008514 tmp2 = load_reg(s, rs);
pbrook9ee6e8b2007-11-11 00:04:49 +00008515 if (op)
pbrookd9ba4832008-03-31 03:46:50 +00008516 tcg_gen_sub_i32(tmp, tmp2, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008517 else
pbrookd9ba4832008-03-31 03:46:50 +00008518 tcg_gen_add_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008519 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008520 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008521 break;
8522 case 1: /* 16 x 16 -> 32 */
pbrookd9ba4832008-03-31 03:46:50 +00008523 gen_mulxy(tmp, tmp2, op & 2, op & 1);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008524 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008525 if (rs != 15) {
pbrookd9ba4832008-03-31 03:46:50 +00008526 tmp2 = load_reg(s, rs);
8527 gen_helper_add_setq(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008528 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008529 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008530 break;
8531 case 2: /* Dual multiply add. */
8532 case 4: /* Dual multiply subtract. */
8533 if (op)
pbrookd9ba4832008-03-31 03:46:50 +00008534 gen_swap_half(tmp2);
8535 gen_smul_dual(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008536 if (insn & (1 << 22)) {
Peter Maydelle1d177b2011-03-11 10:09:58 +00008537 /* This subtraction cannot overflow. */
pbrookd9ba4832008-03-31 03:46:50 +00008538 tcg_gen_sub_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008539 } else {
Peter Maydelle1d177b2011-03-11 10:09:58 +00008540 /* This addition cannot overflow 32 bits;
8541 * however it may overflow considered as a signed
8542 * operation, in which case we must set the Q flag.
8543 */
8544 gen_helper_add_setq(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008545 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00008546 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008547 if (rs != 15)
8548 {
pbrookd9ba4832008-03-31 03:46:50 +00008549 tmp2 = load_reg(s, rs);
8550 gen_helper_add_setq(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008551 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008552 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008553 break;
8554 case 3: /* 32 * 16 -> 32msb */
8555 if (op)
pbrookd9ba4832008-03-31 03:46:50 +00008556 tcg_gen_sari_i32(tmp2, tmp2, 16);
pbrook9ee6e8b2007-11-11 00:04:49 +00008557 else
pbrookd9ba4832008-03-31 03:46:50 +00008558 gen_sxth(tmp2);
pbrooka7812ae2008-11-17 14:43:54 +00008559 tmp64 = gen_muls_i64_i32(tmp, tmp2);
8560 tcg_gen_shri_i64(tmp64, tmp64, 16);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008561 tmp = tcg_temp_new_i32();
pbrooka7812ae2008-11-17 14:43:54 +00008562 tcg_gen_trunc_i64_i32(tmp, tmp64);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03008563 tcg_temp_free_i64(tmp64);
pbrook9ee6e8b2007-11-11 00:04:49 +00008564 if (rs != 15)
8565 {
pbrookd9ba4832008-03-31 03:46:50 +00008566 tmp2 = load_reg(s, rs);
8567 gen_helper_add_setq(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008568 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008569 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008570 break;
Aurelien Jarno838fa722011-01-06 19:53:56 +01008571 case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
8572 tmp64 = gen_muls_i64_i32(tmp, tmp2);
pbrookd9ba4832008-03-31 03:46:50 +00008573 if (rs != 15) {
Aurelien Jarno838fa722011-01-06 19:53:56 +01008574 tmp = load_reg(s, rs);
8575 if (insn & (1 << 20)) {
8576 tmp64 = gen_addq_msw(tmp64, tmp);
pbrookd9ba4832008-03-31 03:46:50 +00008577 } else {
Aurelien Jarno838fa722011-01-06 19:53:56 +01008578 tmp64 = gen_subq_msw(tmp64, tmp);
pbrookd9ba4832008-03-31 03:46:50 +00008579 }
pbrookd9ba4832008-03-31 03:46:50 +00008580 }
Aurelien Jarno838fa722011-01-06 19:53:56 +01008581 if (insn & (1 << 4)) {
8582 tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
8583 }
8584 tcg_gen_shri_i64(tmp64, tmp64, 32);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008585 tmp = tcg_temp_new_i32();
Aurelien Jarno838fa722011-01-06 19:53:56 +01008586 tcg_gen_trunc_i64_i32(tmp, tmp64);
8587 tcg_temp_free_i64(tmp64);
pbrook9ee6e8b2007-11-11 00:04:49 +00008588 break;
8589 case 7: /* Unsigned sum of absolute differences. */
pbrookd9ba4832008-03-31 03:46:50 +00008590 gen_helper_usad8(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008591 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008592 if (rs != 15) {
pbrookd9ba4832008-03-31 03:46:50 +00008593 tmp2 = load_reg(s, rs);
8594 tcg_gen_add_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008595 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008596 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008597 break;
8598 }
pbrookd9ba4832008-03-31 03:46:50 +00008599 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008600 break;
8601 case 6: case 7: /* 64-bit multiply, Divide. */
8602 op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
pbrook5e3f8782008-03-31 03:47:34 +00008603 tmp = load_reg(s, rn);
8604 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008605 if ((op & 0x50) == 0x10) {
8606 /* sdiv, udiv */
Peter Maydell47789992011-10-19 16:14:06 +00008607 if (!arm_feature(env, ARM_FEATURE_THUMB_DIV)) {
pbrook9ee6e8b2007-11-11 00:04:49 +00008608 goto illegal_op;
Peter Maydell47789992011-10-19 16:14:06 +00008609 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008610 if (op & 0x20)
pbrook5e3f8782008-03-31 03:47:34 +00008611 gen_helper_udiv(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008612 else
pbrook5e3f8782008-03-31 03:47:34 +00008613 gen_helper_sdiv(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008614 tcg_temp_free_i32(tmp2);
pbrook5e3f8782008-03-31 03:47:34 +00008615 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008616 } else if ((op & 0xe) == 0xc) {
8617 /* Dual multiply accumulate long. */
8618 if (op & 1)
pbrook5e3f8782008-03-31 03:47:34 +00008619 gen_swap_half(tmp2);
8620 gen_smul_dual(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008621 if (op & 0x10) {
pbrook5e3f8782008-03-31 03:47:34 +00008622 tcg_gen_sub_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008623 } else {
pbrook5e3f8782008-03-31 03:47:34 +00008624 tcg_gen_add_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008625 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00008626 tcg_temp_free_i32(tmp2);
pbrooka7812ae2008-11-17 14:43:54 +00008627 /* BUGFIX */
8628 tmp64 = tcg_temp_new_i64();
8629 tcg_gen_ext_i32_i64(tmp64, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008630 tcg_temp_free_i32(tmp);
pbrooka7812ae2008-11-17 14:43:54 +00008631 gen_addq(s, tmp64, rs, rd);
8632 gen_storeq_reg(s, rs, rd, tmp64);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03008633 tcg_temp_free_i64(tmp64);
pbrook9ee6e8b2007-11-11 00:04:49 +00008634 } else {
8635 if (op & 0x20) {
8636 /* Unsigned 64-bit multiply */
pbrooka7812ae2008-11-17 14:43:54 +00008637 tmp64 = gen_mulu_i64_i32(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008638 } else {
8639 if (op & 8) {
8640 /* smlalxy */
pbrook5e3f8782008-03-31 03:47:34 +00008641 gen_mulxy(tmp, tmp2, op & 2, op & 1);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008642 tcg_temp_free_i32(tmp2);
pbrooka7812ae2008-11-17 14:43:54 +00008643 tmp64 = tcg_temp_new_i64();
8644 tcg_gen_ext_i32_i64(tmp64, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008645 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008646 } else {
8647 /* Signed 64-bit multiply */
pbrooka7812ae2008-11-17 14:43:54 +00008648 tmp64 = gen_muls_i64_i32(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008649 }
8650 }
8651 if (op & 4) {
8652 /* umaal */
pbrooka7812ae2008-11-17 14:43:54 +00008653 gen_addq_lo(s, tmp64, rs);
8654 gen_addq_lo(s, tmp64, rd);
pbrook9ee6e8b2007-11-11 00:04:49 +00008655 } else if (op & 0x40) {
8656 /* 64-bit accumulate. */
pbrooka7812ae2008-11-17 14:43:54 +00008657 gen_addq(s, tmp64, rs, rd);
pbrook9ee6e8b2007-11-11 00:04:49 +00008658 }
pbrooka7812ae2008-11-17 14:43:54 +00008659 gen_storeq_reg(s, rs, rd, tmp64);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03008660 tcg_temp_free_i64(tmp64);
pbrook9ee6e8b2007-11-11 00:04:49 +00008661 }
8662 break;
8663 }
8664 break;
8665 case 6: case 7: case 14: case 15:
8666 /* Coprocessor. */
8667 if (((insn >> 24) & 3) == 3) {
8668 /* Translate into the equivalent ARM encoding. */
Juha Riihimäkif06053e2011-02-11 13:35:25 +00008669 insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
pbrook9ee6e8b2007-11-11 00:04:49 +00008670 if (disas_neon_data_insn(env, s, insn))
8671 goto illegal_op;
8672 } else {
8673 if (insn & (1 << 28))
8674 goto illegal_op;
8675 if (disas_coproc_insn (env, s, insn))
8676 goto illegal_op;
8677 }
8678 break;
8679 case 8: case 9: case 10: case 11:
8680 if (insn & (1 << 15)) {
8681 /* Branches, misc control. */
8682 if (insn & 0x5000) {
8683 /* Unconditional branch. */
8684 /* signextend(hw1[10:0]) -> offset[:12]. */
8685 offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff;
8686 /* hw1[10:0] -> offset[11:1]. */
8687 offset |= (insn & 0x7ff) << 1;
8688 /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22]
8689 offset[24:22] already have the same value because of the
8690 sign extension above. */
8691 offset ^= ((~insn) & (1 << 13)) << 10;
8692 offset ^= ((~insn) & (1 << 11)) << 11;
8693
pbrook9ee6e8b2007-11-11 00:04:49 +00008694 if (insn & (1 << 14)) {
8695 /* Branch and link. */
Filip Navara3174f8e2009-10-15 13:14:28 +02008696 tcg_gen_movi_i32(cpu_R[14], s->pc | 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008697 }
8698
pbrookb0109802008-03-31 03:47:03 +00008699 offset += s->pc;
pbrook9ee6e8b2007-11-11 00:04:49 +00008700 if (insn & (1 << 12)) {
8701 /* b/bl */
pbrookb0109802008-03-31 03:47:03 +00008702 gen_jmp(s, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00008703 } else {
8704 /* blx */
pbrookb0109802008-03-31 03:47:03 +00008705 offset &= ~(uint32_t)2;
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04008706 /* thumb2 bx, no need to check */
pbrookb0109802008-03-31 03:47:03 +00008707 gen_bx_im(s, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00008708 }
8709 } else if (((insn >> 23) & 7) == 7) {
8710 /* Misc control */
8711 if (insn & (1 << 13))
8712 goto illegal_op;
8713
8714 if (insn & (1 << 26)) {
8715 /* Secure monitor call (v6Z) */
8716 goto illegal_op; /* not implemented. */
8717 } else {
8718 op = (insn >> 20) & 7;
8719 switch (op) {
8720 case 0: /* msr cpsr. */
8721 if (IS_M(env)) {
pbrook8984bd22008-03-31 03:47:48 +00008722 tmp = load_reg(s, rn);
8723 addr = tcg_const_i32(insn & 0xff);
8724 gen_helper_v7m_msr(cpu_env, addr, tmp);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03008725 tcg_temp_free_i32(addr);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008726 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008727 gen_lookup_tb(s);
8728 break;
8729 }
8730 /* fall through */
8731 case 1: /* msr spsr. */
8732 if (IS_M(env))
8733 goto illegal_op;
Filip Navara2fbac542009-10-15 12:43:04 +02008734 tmp = load_reg(s, rn);
8735 if (gen_set_psr(s,
pbrook9ee6e8b2007-11-11 00:04:49 +00008736 msr_mask(env, s, (insn >> 8) & 0xf, op == 1),
Filip Navara2fbac542009-10-15 12:43:04 +02008737 op == 1, tmp))
pbrook9ee6e8b2007-11-11 00:04:49 +00008738 goto illegal_op;
8739 break;
8740 case 2: /* cps, nop-hint. */
8741 if (((insn >> 8) & 7) == 0) {
8742 gen_nop_hint(s, insn & 0xff);
8743 }
8744 /* Implemented as NOP in user mode. */
8745 if (IS_USER(s))
8746 break;
8747 offset = 0;
8748 imm = 0;
8749 if (insn & (1 << 10)) {
8750 if (insn & (1 << 7))
8751 offset |= CPSR_A;
8752 if (insn & (1 << 6))
8753 offset |= CPSR_I;
8754 if (insn & (1 << 5))
8755 offset |= CPSR_F;
8756 if (insn & (1 << 9))
8757 imm = CPSR_A | CPSR_I | CPSR_F;
8758 }
8759 if (insn & (1 << 8)) {
8760 offset |= 0x1f;
8761 imm |= (insn & 0x1f);
8762 }
8763 if (offset) {
Filip Navara2fbac542009-10-15 12:43:04 +02008764 gen_set_psr_im(s, offset, 0, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008765 }
8766 break;
8767 case 3: /* Special control operations. */
Paul Brook426f5ab2009-11-22 21:35:13 +00008768 ARCH(7);
pbrook9ee6e8b2007-11-11 00:04:49 +00008769 op = (insn >> 4) & 0xf;
8770 switch (op) {
8771 case 2: /* clrex */
Paul Brook426f5ab2009-11-22 21:35:13 +00008772 gen_clrex(s);
pbrook9ee6e8b2007-11-11 00:04:49 +00008773 break;
8774 case 4: /* dsb */
8775 case 5: /* dmb */
8776 case 6: /* isb */
8777 /* These execute as NOPs. */
pbrook9ee6e8b2007-11-11 00:04:49 +00008778 break;
8779 default:
8780 goto illegal_op;
8781 }
8782 break;
8783 case 4: /* bxj */
8784 /* Trivial implementation equivalent to bx. */
pbrookd9ba4832008-03-31 03:46:50 +00008785 tmp = load_reg(s, rn);
8786 gen_bx(s, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008787 break;
8788 case 5: /* Exception return. */
Rabin Vincentb8b45b62010-02-15 00:02:35 +05308789 if (IS_USER(s)) {
8790 goto illegal_op;
8791 }
8792 if (rn != 14 || rd != 15) {
8793 goto illegal_op;
8794 }
8795 tmp = load_reg(s, rn);
8796 tcg_gen_subi_i32(tmp, tmp, insn & 0xff);
8797 gen_exception_return(s, tmp);
8798 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00008799 case 6: /* mrs cpsr. */
Peter Maydell7d1b0092011-03-06 21:39:54 +00008800 tmp = tcg_temp_new_i32();
pbrook9ee6e8b2007-11-11 00:04:49 +00008801 if (IS_M(env)) {
pbrook8984bd22008-03-31 03:47:48 +00008802 addr = tcg_const_i32(insn & 0xff);
8803 gen_helper_v7m_mrs(tmp, cpu_env, addr);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03008804 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00008805 } else {
pbrook8984bd22008-03-31 03:47:48 +00008806 gen_helper_cpsr_read(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008807 }
pbrook8984bd22008-03-31 03:47:48 +00008808 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008809 break;
8810 case 7: /* mrs spsr. */
8811 /* Not accessible in user mode. */
8812 if (IS_USER(s) || IS_M(env))
8813 goto illegal_op;
pbrookd9ba4832008-03-31 03:46:50 +00008814 tmp = load_cpu_field(spsr);
8815 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008816 break;
8817 }
8818 }
8819 } else {
8820 /* Conditional branch. */
8821 op = (insn >> 22) & 0xf;
8822 /* Generate a conditional jump to next instruction. */
8823 s->condlabel = gen_new_label();
pbrookd9ba4832008-03-31 03:46:50 +00008824 gen_test_cc(op ^ 1, s->condlabel);
pbrook9ee6e8b2007-11-11 00:04:49 +00008825 s->condjmp = 1;
8826
8827 /* offset[11:1] = insn[10:0] */
8828 offset = (insn & 0x7ff) << 1;
8829 /* offset[17:12] = insn[21:16]. */
8830 offset |= (insn & 0x003f0000) >> 4;
8831 /* offset[31:20] = insn[26]. */
8832 offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11;
8833 /* offset[18] = insn[13]. */
8834 offset |= (insn & (1 << 13)) << 5;
8835 /* offset[19] = insn[11]. */
8836 offset |= (insn & (1 << 11)) << 8;
8837
8838 /* jump to the offset */
pbrookb0109802008-03-31 03:47:03 +00008839 gen_jmp(s, s->pc + offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00008840 }
8841 } else {
8842 /* Data processing immediate. */
8843 if (insn & (1 << 25)) {
8844 if (insn & (1 << 24)) {
8845 if (insn & (1 << 20))
8846 goto illegal_op;
8847 /* Bitfield/Saturate. */
8848 op = (insn >> 21) & 7;
8849 imm = insn & 0x1f;
8850 shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
pbrook6ddbc6e2008-03-31 03:46:33 +00008851 if (rn == 15) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008852 tmp = tcg_temp_new_i32();
pbrook6ddbc6e2008-03-31 03:46:33 +00008853 tcg_gen_movi_i32(tmp, 0);
8854 } else {
8855 tmp = load_reg(s, rn);
8856 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008857 switch (op) {
8858 case 2: /* Signed bitfield extract. */
8859 imm++;
8860 if (shift + imm > 32)
8861 goto illegal_op;
8862 if (imm < 32)
pbrook6ddbc6e2008-03-31 03:46:33 +00008863 gen_sbfx(tmp, shift, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008864 break;
8865 case 6: /* Unsigned bitfield extract. */
8866 imm++;
8867 if (shift + imm > 32)
8868 goto illegal_op;
8869 if (imm < 32)
pbrook6ddbc6e2008-03-31 03:46:33 +00008870 gen_ubfx(tmp, shift, (1u << imm) - 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008871 break;
8872 case 3: /* Bitfield insert/clear. */
8873 if (imm < shift)
8874 goto illegal_op;
8875 imm = imm + 1 - shift;
8876 if (imm != 32) {
pbrook6ddbc6e2008-03-31 03:46:33 +00008877 tmp2 = load_reg(s, rd);
pbrook8f8e3aa2008-03-31 03:48:01 +00008878 gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1);
Peter Maydell7d1b0092011-03-06 21:39:54 +00008879 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008880 }
8881 break;
8882 case 7:
8883 goto illegal_op;
8884 default: /* Saturate. */
pbrook9ee6e8b2007-11-11 00:04:49 +00008885 if (shift) {
8886 if (op & 1)
pbrook6ddbc6e2008-03-31 03:46:33 +00008887 tcg_gen_sari_i32(tmp, tmp, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00008888 else
pbrook6ddbc6e2008-03-31 03:46:33 +00008889 tcg_gen_shli_i32(tmp, tmp, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00008890 }
pbrook6ddbc6e2008-03-31 03:46:33 +00008891 tmp2 = tcg_const_i32(imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008892 if (op & 4) {
8893 /* Unsigned. */
pbrook9ee6e8b2007-11-11 00:04:49 +00008894 if ((op & 1) && shift == 0)
pbrook6ddbc6e2008-03-31 03:46:33 +00008895 gen_helper_usat16(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008896 else
pbrook6ddbc6e2008-03-31 03:46:33 +00008897 gen_helper_usat(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008898 } else {
8899 /* Signed. */
pbrook9ee6e8b2007-11-11 00:04:49 +00008900 if ((op & 1) && shift == 0)
pbrook6ddbc6e2008-03-31 03:46:33 +00008901 gen_helper_ssat16(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008902 else
pbrook6ddbc6e2008-03-31 03:46:33 +00008903 gen_helper_ssat(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008904 }
Juha Riihimäkib75263d2009-10-22 15:17:36 +03008905 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008906 break;
8907 }
pbrook6ddbc6e2008-03-31 03:46:33 +00008908 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008909 } else {
8910 imm = ((insn & 0x04000000) >> 15)
8911 | ((insn & 0x7000) >> 4) | (insn & 0xff);
8912 if (insn & (1 << 22)) {
8913 /* 16-bit immediate. */
8914 imm |= (insn >> 4) & 0xf000;
8915 if (insn & (1 << 23)) {
8916 /* movt */
pbrook5e3f8782008-03-31 03:47:34 +00008917 tmp = load_reg(s, rd);
pbrook86831432008-05-11 12:22:01 +00008918 tcg_gen_ext16u_i32(tmp, tmp);
pbrook5e3f8782008-03-31 03:47:34 +00008919 tcg_gen_ori_i32(tmp, tmp, imm << 16);
pbrook9ee6e8b2007-11-11 00:04:49 +00008920 } else {
8921 /* movw */
Peter Maydell7d1b0092011-03-06 21:39:54 +00008922 tmp = tcg_temp_new_i32();
pbrook5e3f8782008-03-31 03:47:34 +00008923 tcg_gen_movi_i32(tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008924 }
8925 } else {
8926 /* Add/sub 12-bit immediate. */
8927 if (rn == 15) {
pbrookb0109802008-03-31 03:47:03 +00008928 offset = s->pc & ~(uint32_t)3;
pbrook9ee6e8b2007-11-11 00:04:49 +00008929 if (insn & (1 << 23))
pbrookb0109802008-03-31 03:47:03 +00008930 offset -= imm;
pbrook9ee6e8b2007-11-11 00:04:49 +00008931 else
pbrookb0109802008-03-31 03:47:03 +00008932 offset += imm;
Peter Maydell7d1b0092011-03-06 21:39:54 +00008933 tmp = tcg_temp_new_i32();
pbrook5e3f8782008-03-31 03:47:34 +00008934 tcg_gen_movi_i32(tmp, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00008935 } else {
pbrook5e3f8782008-03-31 03:47:34 +00008936 tmp = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00008937 if (insn & (1 << 23))
pbrook5e3f8782008-03-31 03:47:34 +00008938 tcg_gen_subi_i32(tmp, tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008939 else
pbrook5e3f8782008-03-31 03:47:34 +00008940 tcg_gen_addi_i32(tmp, tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008941 }
8942 }
pbrook5e3f8782008-03-31 03:47:34 +00008943 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008944 }
8945 } else {
8946 int shifter_out = 0;
8947 /* modified 12-bit immediate. */
8948 shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12);
8949 imm = (insn & 0xff);
8950 switch (shift) {
8951 case 0: /* XY */
8952 /* Nothing to do. */
8953 break;
8954 case 1: /* 00XY00XY */
8955 imm |= imm << 16;
8956 break;
8957 case 2: /* XY00XY00 */
8958 imm |= imm << 16;
8959 imm <<= 8;
8960 break;
8961 case 3: /* XYXYXYXY */
8962 imm |= imm << 16;
8963 imm |= imm << 8;
8964 break;
8965 default: /* Rotated constant. */
8966 shift = (shift << 1) | (imm >> 7);
8967 imm |= 0x80;
8968 imm = imm << (32 - shift);
8969 shifter_out = 1;
8970 break;
8971 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00008972 tmp2 = tcg_temp_new_i32();
Filip Navara3174f8e2009-10-15 13:14:28 +02008973 tcg_gen_movi_i32(tmp2, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008974 rn = (insn >> 16) & 0xf;
Filip Navara3174f8e2009-10-15 13:14:28 +02008975 if (rn == 15) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008976 tmp = tcg_temp_new_i32();
Filip Navara3174f8e2009-10-15 13:14:28 +02008977 tcg_gen_movi_i32(tmp, 0);
8978 } else {
8979 tmp = load_reg(s, rn);
8980 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008981 op = (insn >> 21) & 0xf;
8982 if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
Filip Navara3174f8e2009-10-15 13:14:28 +02008983 shifter_out, tmp, tmp2))
pbrook9ee6e8b2007-11-11 00:04:49 +00008984 goto illegal_op;
Peter Maydell7d1b0092011-03-06 21:39:54 +00008985 tcg_temp_free_i32(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00008986 rd = (insn >> 8) & 0xf;
8987 if (rd != 15) {
Filip Navara3174f8e2009-10-15 13:14:28 +02008988 store_reg(s, rd, tmp);
8989 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00008990 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008991 }
8992 }
8993 }
8994 break;
8995 case 12: /* Load/store single data item. */
8996 {
8997 int postinc = 0;
8998 int writeback = 0;
pbrookb0109802008-03-31 03:47:03 +00008999 int user;
pbrook9ee6e8b2007-11-11 00:04:49 +00009000 if ((insn & 0x01100000) == 0x01000000) {
9001 if (disas_neon_ls_insn(env, s, insn))
9002 goto illegal_op;
9003 break;
9004 }
Peter Maydella2fdc892011-02-03 19:43:25 +00009005 op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
9006 if (rs == 15) {
9007 if (!(insn & (1 << 20))) {
9008 goto illegal_op;
9009 }
9010 if (op != 2) {
9011 /* Byte or halfword load space with dest == r15 : memory hints.
9012 * Catch them early so we don't emit pointless addressing code.
9013 * This space is a mix of:
9014 * PLD/PLDW/PLI, which we implement as NOPs (note that unlike
9015 * the ARM encodings, PLDW space doesn't UNDEF for non-v7MP
9016 * cores)
9017 * unallocated hints, which must be treated as NOPs
9018 * UNPREDICTABLE space, which we NOP or UNDEF depending on
9019 * which is easiest for the decoding logic
9020 * Some space which must UNDEF
9021 */
9022 int op1 = (insn >> 23) & 3;
9023 int op2 = (insn >> 6) & 0x3f;
9024 if (op & 2) {
9025 goto illegal_op;
9026 }
9027 if (rn == 15) {
Peter Maydell02afbf62011-11-24 19:33:31 +01009028 /* UNPREDICTABLE, unallocated hint or
9029 * PLD/PLDW/PLI (literal)
9030 */
Peter Maydella2fdc892011-02-03 19:43:25 +00009031 return 0;
9032 }
9033 if (op1 & 1) {
Peter Maydell02afbf62011-11-24 19:33:31 +01009034 return 0; /* PLD/PLDW/PLI or unallocated hint */
Peter Maydella2fdc892011-02-03 19:43:25 +00009035 }
9036 if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) {
Peter Maydell02afbf62011-11-24 19:33:31 +01009037 return 0; /* PLD/PLDW/PLI or unallocated hint */
Peter Maydella2fdc892011-02-03 19:43:25 +00009038 }
9039 /* UNDEF space, or an UNPREDICTABLE */
9040 return 1;
9041 }
9042 }
pbrookb0109802008-03-31 03:47:03 +00009043 user = IS_USER(s);
pbrook9ee6e8b2007-11-11 00:04:49 +00009044 if (rn == 15) {
Peter Maydell7d1b0092011-03-06 21:39:54 +00009045 addr = tcg_temp_new_i32();
pbrook9ee6e8b2007-11-11 00:04:49 +00009046 /* PC relative. */
9047 /* s->pc has already been incremented by 4. */
9048 imm = s->pc & 0xfffffffc;
9049 if (insn & (1 << 23))
9050 imm += insn & 0xfff;
9051 else
9052 imm -= insn & 0xfff;
pbrookb0109802008-03-31 03:47:03 +00009053 tcg_gen_movi_i32(addr, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00009054 } else {
pbrookb0109802008-03-31 03:47:03 +00009055 addr = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00009056 if (insn & (1 << 23)) {
9057 /* Positive offset. */
9058 imm = insn & 0xfff;
pbrookb0109802008-03-31 03:47:03 +00009059 tcg_gen_addi_i32(addr, addr, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00009060 } else {
pbrook9ee6e8b2007-11-11 00:04:49 +00009061 imm = insn & 0xff;
Peter Maydell2a0308c2011-03-10 16:48:49 +00009062 switch ((insn >> 8) & 0xf) {
9063 case 0x0: /* Shifted Register. */
pbrook9ee6e8b2007-11-11 00:04:49 +00009064 shift = (insn >> 4) & 0xf;
Peter Maydell2a0308c2011-03-10 16:48:49 +00009065 if (shift > 3) {
9066 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00009067 goto illegal_op;
Peter Maydell2a0308c2011-03-10 16:48:49 +00009068 }
pbrookb26eefb2008-03-31 03:44:26 +00009069 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00009070 if (shift)
pbrookb26eefb2008-03-31 03:44:26 +00009071 tcg_gen_shli_i32(tmp, tmp, shift);
pbrookb0109802008-03-31 03:47:03 +00009072 tcg_gen_add_i32(addr, addr, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009073 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009074 break;
Peter Maydell2a0308c2011-03-10 16:48:49 +00009075 case 0xc: /* Negative offset. */
pbrookb0109802008-03-31 03:47:03 +00009076 tcg_gen_addi_i32(addr, addr, -imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00009077 break;
Peter Maydell2a0308c2011-03-10 16:48:49 +00009078 case 0xe: /* User privilege. */
pbrookb0109802008-03-31 03:47:03 +00009079 tcg_gen_addi_i32(addr, addr, imm);
9080 user = 1;
pbrook9ee6e8b2007-11-11 00:04:49 +00009081 break;
Peter Maydell2a0308c2011-03-10 16:48:49 +00009082 case 0x9: /* Post-decrement. */
pbrook9ee6e8b2007-11-11 00:04:49 +00009083 imm = -imm;
9084 /* Fall through. */
Peter Maydell2a0308c2011-03-10 16:48:49 +00009085 case 0xb: /* Post-increment. */
pbrook9ee6e8b2007-11-11 00:04:49 +00009086 postinc = 1;
9087 writeback = 1;
9088 break;
Peter Maydell2a0308c2011-03-10 16:48:49 +00009089 case 0xd: /* Pre-decrement. */
pbrook9ee6e8b2007-11-11 00:04:49 +00009090 imm = -imm;
9091 /* Fall through. */
Peter Maydell2a0308c2011-03-10 16:48:49 +00009092 case 0xf: /* Pre-increment. */
pbrookb0109802008-03-31 03:47:03 +00009093 tcg_gen_addi_i32(addr, addr, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00009094 writeback = 1;
9095 break;
9096 default:
Peter Maydell2a0308c2011-03-10 16:48:49 +00009097 tcg_temp_free_i32(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00009098 goto illegal_op;
9099 }
9100 }
9101 }
pbrook9ee6e8b2007-11-11 00:04:49 +00009102 if (insn & (1 << 20)) {
9103 /* Load. */
Peter Maydella2fdc892011-02-03 19:43:25 +00009104 switch (op) {
9105 case 0: tmp = gen_ld8u(addr, user); break;
9106 case 4: tmp = gen_ld8s(addr, user); break;
9107 case 1: tmp = gen_ld16u(addr, user); break;
9108 case 5: tmp = gen_ld16s(addr, user); break;
9109 case 2: tmp = gen_ld32(addr, user); break;
Peter Maydell2a0308c2011-03-10 16:48:49 +00009110 default:
9111 tcg_temp_free_i32(addr);
9112 goto illegal_op;
Peter Maydella2fdc892011-02-03 19:43:25 +00009113 }
9114 if (rs == 15) {
9115 gen_bx(s, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009116 } else {
Peter Maydella2fdc892011-02-03 19:43:25 +00009117 store_reg(s, rs, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009118 }
9119 } else {
9120 /* Store. */
pbrookb0109802008-03-31 03:47:03 +00009121 tmp = load_reg(s, rs);
pbrook9ee6e8b2007-11-11 00:04:49 +00009122 switch (op) {
pbrookb0109802008-03-31 03:47:03 +00009123 case 0: gen_st8(tmp, addr, user); break;
9124 case 1: gen_st16(tmp, addr, user); break;
9125 case 2: gen_st32(tmp, addr, user); break;
Peter Maydell2a0308c2011-03-10 16:48:49 +00009126 default:
9127 tcg_temp_free_i32(addr);
9128 goto illegal_op;
pbrook9ee6e8b2007-11-11 00:04:49 +00009129 }
9130 }
9131 if (postinc)
pbrookb0109802008-03-31 03:47:03 +00009132 tcg_gen_addi_i32(addr, addr, imm);
9133 if (writeback) {
9134 store_reg(s, rn, addr);
9135 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00009136 tcg_temp_free_i32(addr);
pbrookb0109802008-03-31 03:47:03 +00009137 }
pbrook9ee6e8b2007-11-11 00:04:49 +00009138 }
9139 break;
9140 default:
9141 goto illegal_op;
9142 }
9143 return 0;
9144illegal_op:
9145 return 1;
9146}
9147
9148static void disas_thumb_insn(CPUState *env, DisasContext *s)
bellard99c475a2005-01-31 20:45:13 +00009149{
9150 uint32_t val, insn, op, rm, rn, rd, shift, cond;
9151 int32_t offset;
9152 int i;
pbrookb26eefb2008-03-31 03:44:26 +00009153 TCGv tmp;
pbrookd9ba4832008-03-31 03:46:50 +00009154 TCGv tmp2;
pbrookb0109802008-03-31 03:47:03 +00009155 TCGv addr;
bellard99c475a2005-01-31 20:45:13 +00009156
pbrook9ee6e8b2007-11-11 00:04:49 +00009157 if (s->condexec_mask) {
9158 cond = s->condexec_cond;
Johan Bengtssonbedd2912010-03-17 13:56:07 +01009159 if (cond != 0x0e) { /* Skip conditional when condition is AL. */
9160 s->condlabel = gen_new_label();
9161 gen_test_cc(cond ^ 1, s->condlabel);
9162 s->condjmp = 1;
9163 }
pbrook9ee6e8b2007-11-11 00:04:49 +00009164 }
9165
bellardb5ff1b32005-11-26 10:38:39 +00009166 insn = lduw_code(s->pc);
bellard99c475a2005-01-31 20:45:13 +00009167 s->pc += 2;
bellardb5ff1b32005-11-26 10:38:39 +00009168
bellard99c475a2005-01-31 20:45:13 +00009169 switch (insn >> 12) {
9170 case 0: case 1:
Filip Navara396e4672009-10-15 12:55:34 +02009171
bellard99c475a2005-01-31 20:45:13 +00009172 rd = insn & 7;
9173 op = (insn >> 11) & 3;
9174 if (op == 3) {
9175 /* add/subtract */
9176 rn = (insn >> 3) & 7;
Filip Navara396e4672009-10-15 12:55:34 +02009177 tmp = load_reg(s, rn);
bellard99c475a2005-01-31 20:45:13 +00009178 if (insn & (1 << 10)) {
9179 /* immediate */
Peter Maydell7d1b0092011-03-06 21:39:54 +00009180 tmp2 = tcg_temp_new_i32();
Filip Navara396e4672009-10-15 12:55:34 +02009181 tcg_gen_movi_i32(tmp2, (insn >> 6) & 7);
bellard99c475a2005-01-31 20:45:13 +00009182 } else {
9183 /* reg */
9184 rm = (insn >> 6) & 7;
Filip Navara396e4672009-10-15 12:55:34 +02009185 tmp2 = load_reg(s, rm);
bellard99c475a2005-01-31 20:45:13 +00009186 }
pbrook9ee6e8b2007-11-11 00:04:49 +00009187 if (insn & (1 << 9)) {
9188 if (s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009189 tcg_gen_sub_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009190 else
Filip Navara396e4672009-10-15 12:55:34 +02009191 gen_helper_sub_cc(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009192 } else {
9193 if (s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009194 tcg_gen_add_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009195 else
Filip Navara396e4672009-10-15 12:55:34 +02009196 gen_helper_add_cc(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009197 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00009198 tcg_temp_free_i32(tmp2);
Filip Navara396e4672009-10-15 12:55:34 +02009199 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00009200 } else {
9201 /* shift immediate */
9202 rm = (insn >> 3) & 7;
9203 shift = (insn >> 6) & 0x1f;
pbrook9a119ff2008-03-31 03:45:35 +00009204 tmp = load_reg(s, rm);
9205 gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0);
9206 if (!s->condexec_mask)
9207 gen_logic_CC(tmp);
9208 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00009209 }
9210 break;
9211 case 2: case 3:
9212 /* arithmetic large immediate */
9213 op = (insn >> 11) & 3;
9214 rd = (insn >> 8) & 0x7;
Filip Navara396e4672009-10-15 12:55:34 +02009215 if (op == 0) { /* mov */
Peter Maydell7d1b0092011-03-06 21:39:54 +00009216 tmp = tcg_temp_new_i32();
Filip Navara396e4672009-10-15 12:55:34 +02009217 tcg_gen_movi_i32(tmp, insn & 0xff);
pbrook9ee6e8b2007-11-11 00:04:49 +00009218 if (!s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009219 gen_logic_CC(tmp);
9220 store_reg(s, rd, tmp);
9221 } else {
9222 tmp = load_reg(s, rd);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009223 tmp2 = tcg_temp_new_i32();
Filip Navara396e4672009-10-15 12:55:34 +02009224 tcg_gen_movi_i32(tmp2, insn & 0xff);
9225 switch (op) {
9226 case 1: /* cmp */
9227 gen_helper_sub_cc(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009228 tcg_temp_free_i32(tmp);
9229 tcg_temp_free_i32(tmp2);
Filip Navara396e4672009-10-15 12:55:34 +02009230 break;
9231 case 2: /* add */
9232 if (s->condexec_mask)
9233 tcg_gen_add_i32(tmp, tmp, tmp2);
9234 else
9235 gen_helper_add_cc(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009236 tcg_temp_free_i32(tmp2);
Filip Navara396e4672009-10-15 12:55:34 +02009237 store_reg(s, rd, tmp);
9238 break;
9239 case 3: /* sub */
9240 if (s->condexec_mask)
9241 tcg_gen_sub_i32(tmp, tmp, tmp2);
9242 else
9243 gen_helper_sub_cc(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009244 tcg_temp_free_i32(tmp2);
Filip Navara396e4672009-10-15 12:55:34 +02009245 store_reg(s, rd, tmp);
9246 break;
9247 }
bellard99c475a2005-01-31 20:45:13 +00009248 }
bellard99c475a2005-01-31 20:45:13 +00009249 break;
9250 case 4:
9251 if (insn & (1 << 11)) {
9252 rd = (insn >> 8) & 7;
bellard5899f382005-04-27 20:25:20 +00009253 /* load pc-relative. Bit 1 of PC is ignored. */
9254 val = s->pc + 2 + ((insn & 0xff) * 4);
9255 val &= ~(uint32_t)2;
Peter Maydell7d1b0092011-03-06 21:39:54 +00009256 addr = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +00009257 tcg_gen_movi_i32(addr, val);
9258 tmp = gen_ld32(addr, IS_USER(s));
Peter Maydell7d1b0092011-03-06 21:39:54 +00009259 tcg_temp_free_i32(addr);
pbrookb0109802008-03-31 03:47:03 +00009260 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00009261 break;
9262 }
9263 if (insn & (1 << 10)) {
9264 /* data processing extended or blx */
9265 rd = (insn & 7) | ((insn >> 4) & 8);
9266 rm = (insn >> 3) & 0xf;
9267 op = (insn >> 8) & 3;
9268 switch (op) {
9269 case 0: /* add */
Filip Navara396e4672009-10-15 12:55:34 +02009270 tmp = load_reg(s, rd);
9271 tmp2 = load_reg(s, rm);
9272 tcg_gen_add_i32(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009273 tcg_temp_free_i32(tmp2);
Filip Navara396e4672009-10-15 12:55:34 +02009274 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00009275 break;
9276 case 1: /* cmp */
Filip Navara396e4672009-10-15 12:55:34 +02009277 tmp = load_reg(s, rd);
9278 tmp2 = load_reg(s, rm);
9279 gen_helper_sub_cc(tmp, tmp, tmp2);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009280 tcg_temp_free_i32(tmp2);
9281 tcg_temp_free_i32(tmp);
bellard99c475a2005-01-31 20:45:13 +00009282 break;
9283 case 2: /* mov/cpy */
Filip Navara396e4672009-10-15 12:55:34 +02009284 tmp = load_reg(s, rm);
9285 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00009286 break;
9287 case 3:/* branch [and link] exchange thumb register */
pbrookb0109802008-03-31 03:47:03 +00009288 tmp = load_reg(s, rm);
bellard99c475a2005-01-31 20:45:13 +00009289 if (insn & (1 << 7)) {
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04009290 ARCH(5);
bellard99c475a2005-01-31 20:45:13 +00009291 val = (uint32_t)s->pc | 1;
Peter Maydell7d1b0092011-03-06 21:39:54 +00009292 tmp2 = tcg_temp_new_i32();
pbrookb0109802008-03-31 03:47:03 +00009293 tcg_gen_movi_i32(tmp2, val);
9294 store_reg(s, 14, tmp2);
bellard99c475a2005-01-31 20:45:13 +00009295 }
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04009296 /* already thumb, no need to check */
pbrookd9ba4832008-03-31 03:46:50 +00009297 gen_bx(s, tmp);
bellard99c475a2005-01-31 20:45:13 +00009298 break;
9299 }
9300 break;
9301 }
9302
9303 /* data processing register */
9304 rd = insn & 7;
9305 rm = (insn >> 3) & 7;
9306 op = (insn >> 6) & 0xf;
9307 if (op == 2 || op == 3 || op == 4 || op == 7) {
9308 /* the shift/rotate ops want the operands backwards */
9309 val = rm;
9310 rm = rd;
9311 rd = val;
9312 val = 1;
9313 } else {
9314 val = 0;
9315 }
9316
Filip Navara396e4672009-10-15 12:55:34 +02009317 if (op == 9) { /* neg */
Peter Maydell7d1b0092011-03-06 21:39:54 +00009318 tmp = tcg_temp_new_i32();
Filip Navara396e4672009-10-15 12:55:34 +02009319 tcg_gen_movi_i32(tmp, 0);
9320 } else if (op != 0xf) { /* mvn doesn't read its first operand */
9321 tmp = load_reg(s, rd);
9322 } else {
9323 TCGV_UNUSED(tmp);
9324 }
bellard99c475a2005-01-31 20:45:13 +00009325
Filip Navara396e4672009-10-15 12:55:34 +02009326 tmp2 = load_reg(s, rm);
bellard5899f382005-04-27 20:25:20 +00009327 switch (op) {
bellard99c475a2005-01-31 20:45:13 +00009328 case 0x0: /* and */
Filip Navara396e4672009-10-15 12:55:34 +02009329 tcg_gen_and_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009330 if (!s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009331 gen_logic_CC(tmp);
bellard99c475a2005-01-31 20:45:13 +00009332 break;
9333 case 0x1: /* eor */
Filip Navara396e4672009-10-15 12:55:34 +02009334 tcg_gen_xor_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009335 if (!s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009336 gen_logic_CC(tmp);
bellard99c475a2005-01-31 20:45:13 +00009337 break;
9338 case 0x2: /* lsl */
pbrook9ee6e8b2007-11-11 00:04:49 +00009339 if (s->condexec_mask) {
Filip Navara396e4672009-10-15 12:55:34 +02009340 gen_helper_shl(tmp2, tmp2, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009341 } else {
Filip Navara396e4672009-10-15 12:55:34 +02009342 gen_helper_shl_cc(tmp2, tmp2, tmp);
9343 gen_logic_CC(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009344 }
bellard99c475a2005-01-31 20:45:13 +00009345 break;
9346 case 0x3: /* lsr */
pbrook9ee6e8b2007-11-11 00:04:49 +00009347 if (s->condexec_mask) {
Filip Navara396e4672009-10-15 12:55:34 +02009348 gen_helper_shr(tmp2, tmp2, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009349 } else {
Filip Navara396e4672009-10-15 12:55:34 +02009350 gen_helper_shr_cc(tmp2, tmp2, tmp);
9351 gen_logic_CC(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009352 }
bellard99c475a2005-01-31 20:45:13 +00009353 break;
9354 case 0x4: /* asr */
pbrook9ee6e8b2007-11-11 00:04:49 +00009355 if (s->condexec_mask) {
Filip Navara396e4672009-10-15 12:55:34 +02009356 gen_helper_sar(tmp2, tmp2, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009357 } else {
Filip Navara396e4672009-10-15 12:55:34 +02009358 gen_helper_sar_cc(tmp2, tmp2, tmp);
9359 gen_logic_CC(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009360 }
bellard99c475a2005-01-31 20:45:13 +00009361 break;
9362 case 0x5: /* adc */
pbrook9ee6e8b2007-11-11 00:04:49 +00009363 if (s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009364 gen_adc(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009365 else
Filip Navara396e4672009-10-15 12:55:34 +02009366 gen_helper_adc_cc(tmp, tmp, tmp2);
bellard99c475a2005-01-31 20:45:13 +00009367 break;
9368 case 0x6: /* sbc */
pbrook9ee6e8b2007-11-11 00:04:49 +00009369 if (s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009370 gen_sub_carry(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009371 else
Filip Navara396e4672009-10-15 12:55:34 +02009372 gen_helper_sbc_cc(tmp, tmp, tmp2);
bellard99c475a2005-01-31 20:45:13 +00009373 break;
9374 case 0x7: /* ror */
pbrook9ee6e8b2007-11-11 00:04:49 +00009375 if (s->condexec_mask) {
Aurelien Jarnof669df22009-10-15 16:45:14 +02009376 tcg_gen_andi_i32(tmp, tmp, 0x1f);
9377 tcg_gen_rotr_i32(tmp2, tmp2, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009378 } else {
Filip Navara396e4672009-10-15 12:55:34 +02009379 gen_helper_ror_cc(tmp2, tmp2, tmp);
9380 gen_logic_CC(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009381 }
bellard99c475a2005-01-31 20:45:13 +00009382 break;
9383 case 0x8: /* tst */
Filip Navara396e4672009-10-15 12:55:34 +02009384 tcg_gen_and_i32(tmp, tmp, tmp2);
9385 gen_logic_CC(tmp);
bellard99c475a2005-01-31 20:45:13 +00009386 rd = 16;
bellard5899f382005-04-27 20:25:20 +00009387 break;
bellard99c475a2005-01-31 20:45:13 +00009388 case 0x9: /* neg */
pbrook9ee6e8b2007-11-11 00:04:49 +00009389 if (s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009390 tcg_gen_neg_i32(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009391 else
Filip Navara396e4672009-10-15 12:55:34 +02009392 gen_helper_sub_cc(tmp, tmp, tmp2);
bellard99c475a2005-01-31 20:45:13 +00009393 break;
9394 case 0xa: /* cmp */
Filip Navara396e4672009-10-15 12:55:34 +02009395 gen_helper_sub_cc(tmp, tmp, tmp2);
bellard99c475a2005-01-31 20:45:13 +00009396 rd = 16;
9397 break;
9398 case 0xb: /* cmn */
Filip Navara396e4672009-10-15 12:55:34 +02009399 gen_helper_add_cc(tmp, tmp, tmp2);
bellard99c475a2005-01-31 20:45:13 +00009400 rd = 16;
9401 break;
9402 case 0xc: /* orr */
Filip Navara396e4672009-10-15 12:55:34 +02009403 tcg_gen_or_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009404 if (!s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009405 gen_logic_CC(tmp);
bellard99c475a2005-01-31 20:45:13 +00009406 break;
9407 case 0xd: /* mul */
Juha.Riihimaki@nokia.com7b2919a2009-10-21 12:17:38 +02009408 tcg_gen_mul_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009409 if (!s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009410 gen_logic_CC(tmp);
bellard99c475a2005-01-31 20:45:13 +00009411 break;
9412 case 0xe: /* bic */
Aurelien Jarnof669df22009-10-15 16:45:14 +02009413 tcg_gen_andc_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009414 if (!s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009415 gen_logic_CC(tmp);
bellard99c475a2005-01-31 20:45:13 +00009416 break;
9417 case 0xf: /* mvn */
Filip Navara396e4672009-10-15 12:55:34 +02009418 tcg_gen_not_i32(tmp2, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00009419 if (!s->condexec_mask)
Filip Navara396e4672009-10-15 12:55:34 +02009420 gen_logic_CC(tmp2);
bellard99c475a2005-01-31 20:45:13 +00009421 val = 1;
bellard5899f382005-04-27 20:25:20 +00009422 rm = rd;
bellard99c475a2005-01-31 20:45:13 +00009423 break;
9424 }
9425 if (rd != 16) {
Filip Navara396e4672009-10-15 12:55:34 +02009426 if (val) {
9427 store_reg(s, rm, tmp2);
9428 if (op != 0xf)
Peter Maydell7d1b0092011-03-06 21:39:54 +00009429 tcg_temp_free_i32(tmp);
Filip Navara396e4672009-10-15 12:55:34 +02009430 } else {
9431 store_reg(s, rd, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009432 tcg_temp_free_i32(tmp2);
Filip Navara396e4672009-10-15 12:55:34 +02009433 }
9434 } else {
Peter Maydell7d1b0092011-03-06 21:39:54 +00009435 tcg_temp_free_i32(tmp);
9436 tcg_temp_free_i32(tmp2);
bellard99c475a2005-01-31 20:45:13 +00009437 }
9438 break;
9439
9440 case 5:
9441 /* load/store register offset. */
9442 rd = insn & 7;
9443 rn = (insn >> 3) & 7;
9444 rm = (insn >> 6) & 7;
9445 op = (insn >> 9) & 7;
pbrookb0109802008-03-31 03:47:03 +00009446 addr = load_reg(s, rn);
pbrookb26eefb2008-03-31 03:44:26 +00009447 tmp = load_reg(s, rm);
pbrookb0109802008-03-31 03:47:03 +00009448 tcg_gen_add_i32(addr, addr, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009449 tcg_temp_free_i32(tmp);
bellard99c475a2005-01-31 20:45:13 +00009450
9451 if (op < 3) /* store */
pbrookb0109802008-03-31 03:47:03 +00009452 tmp = load_reg(s, rd);
bellard99c475a2005-01-31 20:45:13 +00009453
9454 switch (op) {
9455 case 0: /* str */
pbrookb0109802008-03-31 03:47:03 +00009456 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009457 break;
9458 case 1: /* strh */
pbrookb0109802008-03-31 03:47:03 +00009459 gen_st16(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009460 break;
9461 case 2: /* strb */
pbrookb0109802008-03-31 03:47:03 +00009462 gen_st8(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009463 break;
9464 case 3: /* ldrsb */
pbrookb0109802008-03-31 03:47:03 +00009465 tmp = gen_ld8s(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009466 break;
9467 case 4: /* ldr */
pbrookb0109802008-03-31 03:47:03 +00009468 tmp = gen_ld32(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009469 break;
9470 case 5: /* ldrh */
pbrookb0109802008-03-31 03:47:03 +00009471 tmp = gen_ld16u(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009472 break;
9473 case 6: /* ldrb */
pbrookb0109802008-03-31 03:47:03 +00009474 tmp = gen_ld8u(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009475 break;
9476 case 7: /* ldrsh */
pbrookb0109802008-03-31 03:47:03 +00009477 tmp = gen_ld16s(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009478 break;
9479 }
9480 if (op >= 3) /* load */
pbrookb0109802008-03-31 03:47:03 +00009481 store_reg(s, rd, tmp);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009482 tcg_temp_free_i32(addr);
bellard99c475a2005-01-31 20:45:13 +00009483 break;
9484
9485 case 6:
9486 /* load/store word immediate offset */
9487 rd = insn & 7;
9488 rn = (insn >> 3) & 7;
pbrookb0109802008-03-31 03:47:03 +00009489 addr = load_reg(s, rn);
bellard99c475a2005-01-31 20:45:13 +00009490 val = (insn >> 4) & 0x7c;
pbrookb0109802008-03-31 03:47:03 +00009491 tcg_gen_addi_i32(addr, addr, val);
bellard99c475a2005-01-31 20:45:13 +00009492
9493 if (insn & (1 << 11)) {
9494 /* load */
pbrookb0109802008-03-31 03:47:03 +00009495 tmp = gen_ld32(addr, IS_USER(s));
9496 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00009497 } else {
9498 /* store */
pbrookb0109802008-03-31 03:47:03 +00009499 tmp = load_reg(s, rd);
9500 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009501 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00009502 tcg_temp_free_i32(addr);
bellard99c475a2005-01-31 20:45:13 +00009503 break;
9504
9505 case 7:
9506 /* load/store byte immediate offset */
9507 rd = insn & 7;
9508 rn = (insn >> 3) & 7;
pbrookb0109802008-03-31 03:47:03 +00009509 addr = load_reg(s, rn);
bellard99c475a2005-01-31 20:45:13 +00009510 val = (insn >> 6) & 0x1f;
pbrookb0109802008-03-31 03:47:03 +00009511 tcg_gen_addi_i32(addr, addr, val);
bellard99c475a2005-01-31 20:45:13 +00009512
9513 if (insn & (1 << 11)) {
9514 /* load */
pbrookb0109802008-03-31 03:47:03 +00009515 tmp = gen_ld8u(addr, IS_USER(s));
9516 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00009517 } else {
9518 /* store */
pbrookb0109802008-03-31 03:47:03 +00009519 tmp = load_reg(s, rd);
9520 gen_st8(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009521 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00009522 tcg_temp_free_i32(addr);
bellard99c475a2005-01-31 20:45:13 +00009523 break;
9524
9525 case 8:
9526 /* load/store halfword immediate offset */
9527 rd = insn & 7;
9528 rn = (insn >> 3) & 7;
pbrookb0109802008-03-31 03:47:03 +00009529 addr = load_reg(s, rn);
bellard99c475a2005-01-31 20:45:13 +00009530 val = (insn >> 5) & 0x3e;
pbrookb0109802008-03-31 03:47:03 +00009531 tcg_gen_addi_i32(addr, addr, val);
bellard99c475a2005-01-31 20:45:13 +00009532
9533 if (insn & (1 << 11)) {
9534 /* load */
pbrookb0109802008-03-31 03:47:03 +00009535 tmp = gen_ld16u(addr, IS_USER(s));
9536 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00009537 } else {
9538 /* store */
pbrookb0109802008-03-31 03:47:03 +00009539 tmp = load_reg(s, rd);
9540 gen_st16(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009541 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00009542 tcg_temp_free_i32(addr);
bellard99c475a2005-01-31 20:45:13 +00009543 break;
9544
9545 case 9:
9546 /* load/store from stack */
9547 rd = (insn >> 8) & 7;
pbrookb0109802008-03-31 03:47:03 +00009548 addr = load_reg(s, 13);
bellard99c475a2005-01-31 20:45:13 +00009549 val = (insn & 0xff) * 4;
pbrookb0109802008-03-31 03:47:03 +00009550 tcg_gen_addi_i32(addr, addr, val);
bellard99c475a2005-01-31 20:45:13 +00009551
9552 if (insn & (1 << 11)) {
9553 /* load */
pbrookb0109802008-03-31 03:47:03 +00009554 tmp = gen_ld32(addr, IS_USER(s));
9555 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00009556 } else {
9557 /* store */
pbrookb0109802008-03-31 03:47:03 +00009558 tmp = load_reg(s, rd);
9559 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009560 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00009561 tcg_temp_free_i32(addr);
bellard99c475a2005-01-31 20:45:13 +00009562 break;
9563
9564 case 10:
9565 /* add to high reg */
9566 rd = (insn >> 8) & 7;
bellard5899f382005-04-27 20:25:20 +00009567 if (insn & (1 << 11)) {
9568 /* SP */
pbrook5e3f8782008-03-31 03:47:34 +00009569 tmp = load_reg(s, 13);
bellard5899f382005-04-27 20:25:20 +00009570 } else {
9571 /* PC. bit 1 is ignored. */
Peter Maydell7d1b0092011-03-06 21:39:54 +00009572 tmp = tcg_temp_new_i32();
pbrook5e3f8782008-03-31 03:47:34 +00009573 tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
bellard5899f382005-04-27 20:25:20 +00009574 }
bellard99c475a2005-01-31 20:45:13 +00009575 val = (insn & 0xff) * 4;
pbrook5e3f8782008-03-31 03:47:34 +00009576 tcg_gen_addi_i32(tmp, tmp, val);
9577 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00009578 break;
9579
9580 case 11:
9581 /* misc */
9582 op = (insn >> 8) & 0xf;
9583 switch (op) {
9584 case 0:
9585 /* adjust stack pointer */
pbrookb26eefb2008-03-31 03:44:26 +00009586 tmp = load_reg(s, 13);
bellard99c475a2005-01-31 20:45:13 +00009587 val = (insn & 0x7f) * 4;
9588 if (insn & (1 << 7))
balrog6a0d8a12008-04-13 13:25:31 +00009589 val = -(int32_t)val;
pbrookb26eefb2008-03-31 03:44:26 +00009590 tcg_gen_addi_i32(tmp, tmp, val);
9591 store_reg(s, 13, tmp);
bellard99c475a2005-01-31 20:45:13 +00009592 break;
9593
pbrook9ee6e8b2007-11-11 00:04:49 +00009594 case 2: /* sign/zero extend. */
9595 ARCH(6);
9596 rd = insn & 7;
9597 rm = (insn >> 3) & 7;
pbrookb0109802008-03-31 03:47:03 +00009598 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00009599 switch ((insn >> 6) & 3) {
pbrookb0109802008-03-31 03:47:03 +00009600 case 0: gen_sxth(tmp); break;
9601 case 1: gen_sxtb(tmp); break;
9602 case 2: gen_uxth(tmp); break;
9603 case 3: gen_uxtb(tmp); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00009604 }
pbrookb0109802008-03-31 03:47:03 +00009605 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009606 break;
bellard99c475a2005-01-31 20:45:13 +00009607 case 4: case 5: case 0xc: case 0xd:
9608 /* push/pop */
pbrookb0109802008-03-31 03:47:03 +00009609 addr = load_reg(s, 13);
bellard5899f382005-04-27 20:25:20 +00009610 if (insn & (1 << 8))
9611 offset = 4;
bellard99c475a2005-01-31 20:45:13 +00009612 else
bellard5899f382005-04-27 20:25:20 +00009613 offset = 0;
9614 for (i = 0; i < 8; i++) {
9615 if (insn & (1 << i))
9616 offset += 4;
9617 }
9618 if ((insn & (1 << 11)) == 0) {
pbrookb0109802008-03-31 03:47:03 +00009619 tcg_gen_addi_i32(addr, addr, -offset);
bellard5899f382005-04-27 20:25:20 +00009620 }
bellard99c475a2005-01-31 20:45:13 +00009621 for (i = 0; i < 8; i++) {
9622 if (insn & (1 << i)) {
9623 if (insn & (1 << 11)) {
9624 /* pop */
pbrookb0109802008-03-31 03:47:03 +00009625 tmp = gen_ld32(addr, IS_USER(s));
9626 store_reg(s, i, tmp);
bellard99c475a2005-01-31 20:45:13 +00009627 } else {
9628 /* push */
pbrookb0109802008-03-31 03:47:03 +00009629 tmp = load_reg(s, i);
9630 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009631 }
bellard5899f382005-04-27 20:25:20 +00009632 /* advance to the next address. */
pbrookb0109802008-03-31 03:47:03 +00009633 tcg_gen_addi_i32(addr, addr, 4);
bellard99c475a2005-01-31 20:45:13 +00009634 }
9635 }
pbrooka50f5b92008-06-29 15:25:29 +00009636 TCGV_UNUSED(tmp);
bellard99c475a2005-01-31 20:45:13 +00009637 if (insn & (1 << 8)) {
9638 if (insn & (1 << 11)) {
9639 /* pop pc */
pbrookb0109802008-03-31 03:47:03 +00009640 tmp = gen_ld32(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009641 /* don't set the pc until the rest of the instruction
9642 has completed */
9643 } else {
9644 /* push lr */
pbrookb0109802008-03-31 03:47:03 +00009645 tmp = load_reg(s, 14);
9646 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009647 }
pbrookb0109802008-03-31 03:47:03 +00009648 tcg_gen_addi_i32(addr, addr, 4);
bellard99c475a2005-01-31 20:45:13 +00009649 }
bellard5899f382005-04-27 20:25:20 +00009650 if ((insn & (1 << 11)) == 0) {
pbrookb0109802008-03-31 03:47:03 +00009651 tcg_gen_addi_i32(addr, addr, -offset);
bellard5899f382005-04-27 20:25:20 +00009652 }
bellard99c475a2005-01-31 20:45:13 +00009653 /* write back the new stack pointer */
pbrookb0109802008-03-31 03:47:03 +00009654 store_reg(s, 13, addr);
bellard99c475a2005-01-31 20:45:13 +00009655 /* set the new PC value */
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04009656 if ((insn & 0x0900) == 0x0900) {
9657 store_reg_from_load(env, s, 15, tmp);
9658 }
bellard99c475a2005-01-31 20:45:13 +00009659 break;
9660
pbrook9ee6e8b2007-11-11 00:04:49 +00009661 case 1: case 3: case 9: case 11: /* czb */
9662 rm = insn & 7;
pbrookd9ba4832008-03-31 03:46:50 +00009663 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00009664 s->condlabel = gen_new_label();
9665 s->condjmp = 1;
9666 if (insn & (1 << 11))
pbrookcb636692008-05-24 02:22:00 +00009667 tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
pbrook9ee6e8b2007-11-11 00:04:49 +00009668 else
pbrookcb636692008-05-24 02:22:00 +00009669 tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
Peter Maydell7d1b0092011-03-06 21:39:54 +00009670 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009671 offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3;
9672 val = (uint32_t)s->pc + 2;
9673 val += offset;
9674 gen_jmp(s, val);
9675 break;
9676
9677 case 15: /* IT, nop-hint. */
9678 if ((insn & 0xf) == 0) {
9679 gen_nop_hint(s, (insn >> 4) & 0xf);
9680 break;
9681 }
9682 /* If Then. */
9683 s->condexec_cond = (insn >> 4) & 0xe;
9684 s->condexec_mask = insn & 0x1f;
9685 /* No actual code generated for this insn, just setup state. */
9686 break;
9687
pbrook06c949e2006-02-04 19:35:26 +00009688 case 0xe: /* bkpt */
Dmitry Eremin-Solenikovbe5e7a72011-04-04 17:38:44 +04009689 ARCH(5);
Peter Maydellbc4a0de2011-01-14 20:39:19 +01009690 gen_exception_insn(s, 2, EXCP_BKPT);
pbrook06c949e2006-02-04 19:35:26 +00009691 break;
9692
pbrook9ee6e8b2007-11-11 00:04:49 +00009693 case 0xa: /* rev */
9694 ARCH(6);
9695 rn = (insn >> 3) & 0x7;
9696 rd = insn & 0x7;
pbrookb0109802008-03-31 03:47:03 +00009697 tmp = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00009698 switch ((insn >> 6) & 3) {
aurel3266896cb2009-03-13 09:34:48 +00009699 case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
pbrookb0109802008-03-31 03:47:03 +00009700 case 1: gen_rev16(tmp); break;
9701 case 3: gen_revsh(tmp); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00009702 default: goto illegal_op;
9703 }
pbrookb0109802008-03-31 03:47:03 +00009704 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009705 break;
9706
9707 case 6: /* cps */
9708 ARCH(6);
9709 if (IS_USER(s))
9710 break;
9711 if (IS_M(env)) {
pbrook8984bd22008-03-31 03:47:48 +00009712 tmp = tcg_const_i32((insn & (1 << 4)) != 0);
Peter Maydelld3cb6e22012-01-13 17:25:08 +00009713 /* FAULTMASK */
pbrook8984bd22008-03-31 03:47:48 +00009714 if (insn & 1) {
Peter Maydelld3cb6e22012-01-13 17:25:08 +00009715 addr = tcg_const_i32(19);
pbrook8984bd22008-03-31 03:47:48 +00009716 gen_helper_v7m_msr(cpu_env, addr, tmp);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03009717 tcg_temp_free_i32(addr);
pbrook8984bd22008-03-31 03:47:48 +00009718 }
Peter Maydelld3cb6e22012-01-13 17:25:08 +00009719 /* PRIMASK */
pbrook8984bd22008-03-31 03:47:48 +00009720 if (insn & 2) {
Peter Maydelld3cb6e22012-01-13 17:25:08 +00009721 addr = tcg_const_i32(16);
pbrook8984bd22008-03-31 03:47:48 +00009722 gen_helper_v7m_msr(cpu_env, addr, tmp);
Juha Riihimäkib75263d2009-10-22 15:17:36 +03009723 tcg_temp_free_i32(addr);
pbrook8984bd22008-03-31 03:47:48 +00009724 }
Juha Riihimäkib75263d2009-10-22 15:17:36 +03009725 tcg_temp_free_i32(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00009726 gen_lookup_tb(s);
9727 } else {
9728 if (insn & (1 << 4))
9729 shift = CPSR_A | CPSR_I | CPSR_F;
9730 else
9731 shift = 0;
Rabin Vincentfa26df02010-02-15 00:02:34 +05309732 gen_set_psr_im(s, ((insn & 7) << 6), 0, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00009733 }
9734 break;
9735
bellard99c475a2005-01-31 20:45:13 +00009736 default:
9737 goto undef;
9738 }
9739 break;
9740
9741 case 12:
Peter Maydella7d39702011-04-26 18:17:20 +01009742 {
bellard99c475a2005-01-31 20:45:13 +00009743 /* load/store multiple */
Peter Maydella7d39702011-04-26 18:17:20 +01009744 TCGv loaded_var;
9745 TCGV_UNUSED(loaded_var);
bellard99c475a2005-01-31 20:45:13 +00009746 rn = (insn >> 8) & 0x7;
pbrookb0109802008-03-31 03:47:03 +00009747 addr = load_reg(s, rn);
bellard99c475a2005-01-31 20:45:13 +00009748 for (i = 0; i < 8; i++) {
9749 if (insn & (1 << i)) {
bellard99c475a2005-01-31 20:45:13 +00009750 if (insn & (1 << 11)) {
9751 /* load */
pbrookb0109802008-03-31 03:47:03 +00009752 tmp = gen_ld32(addr, IS_USER(s));
Peter Maydella7d39702011-04-26 18:17:20 +01009753 if (i == rn) {
9754 loaded_var = tmp;
9755 } else {
9756 store_reg(s, i, tmp);
9757 }
bellard99c475a2005-01-31 20:45:13 +00009758 } else {
9759 /* store */
pbrookb0109802008-03-31 03:47:03 +00009760 tmp = load_reg(s, i);
9761 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00009762 }
bellard5899f382005-04-27 20:25:20 +00009763 /* advance to the next address */
pbrookb0109802008-03-31 03:47:03 +00009764 tcg_gen_addi_i32(addr, addr, 4);
bellard99c475a2005-01-31 20:45:13 +00009765 }
9766 }
pbrookb0109802008-03-31 03:47:03 +00009767 if ((insn & (1 << rn)) == 0) {
Peter Maydella7d39702011-04-26 18:17:20 +01009768 /* base reg not in list: base register writeback */
pbrookb0109802008-03-31 03:47:03 +00009769 store_reg(s, rn, addr);
9770 } else {
Peter Maydella7d39702011-04-26 18:17:20 +01009771 /* base reg in list: if load, complete it now */
9772 if (insn & (1 << 11)) {
9773 store_reg(s, rn, loaded_var);
9774 }
Peter Maydell7d1b0092011-03-06 21:39:54 +00009775 tcg_temp_free_i32(addr);
pbrookb0109802008-03-31 03:47:03 +00009776 }
bellard99c475a2005-01-31 20:45:13 +00009777 break;
Peter Maydella7d39702011-04-26 18:17:20 +01009778 }
bellard99c475a2005-01-31 20:45:13 +00009779 case 13:
9780 /* conditional branch or swi */
9781 cond = (insn >> 8) & 0xf;
9782 if (cond == 0xe)
9783 goto undef;
9784
9785 if (cond == 0xf) {
9786 /* swi */
balrog422ebf62008-04-16 23:17:02 +00009787 gen_set_pc_im(s->pc);
pbrook9ee6e8b2007-11-11 00:04:49 +00009788 s->is_jmp = DISAS_SWI;
bellard99c475a2005-01-31 20:45:13 +00009789 break;
9790 }
9791 /* generate a conditional jump to next instruction */
bellarde50e6a22005-04-26 20:36:11 +00009792 s->condlabel = gen_new_label();
pbrookd9ba4832008-03-31 03:46:50 +00009793 gen_test_cc(cond ^ 1, s->condlabel);
bellarde50e6a22005-04-26 20:36:11 +00009794 s->condjmp = 1;
bellard99c475a2005-01-31 20:45:13 +00009795
9796 /* jump to the offset */
bellard5899f382005-04-27 20:25:20 +00009797 val = (uint32_t)s->pc + 2;
bellard99c475a2005-01-31 20:45:13 +00009798 offset = ((int32_t)insn << 24) >> 24;
bellard5899f382005-04-27 20:25:20 +00009799 val += offset << 1;
bellard8aaca4c2005-04-23 18:27:52 +00009800 gen_jmp(s, val);
bellard99c475a2005-01-31 20:45:13 +00009801 break;
9802
9803 case 14:
pbrook358bf292006-04-09 14:38:57 +00009804 if (insn & (1 << 11)) {
pbrook9ee6e8b2007-11-11 00:04:49 +00009805 if (disas_thumb2_insn(env, s, insn))
9806 goto undef32;
pbrook358bf292006-04-09 14:38:57 +00009807 break;
9808 }
pbrook9ee6e8b2007-11-11 00:04:49 +00009809 /* unconditional branch */
bellard99c475a2005-01-31 20:45:13 +00009810 val = (uint32_t)s->pc;
9811 offset = ((int32_t)insn << 21) >> 21;
9812 val += (offset << 1) + 2;
bellard8aaca4c2005-04-23 18:27:52 +00009813 gen_jmp(s, val);
bellard99c475a2005-01-31 20:45:13 +00009814 break;
9815
9816 case 15:
pbrook9ee6e8b2007-11-11 00:04:49 +00009817 if (disas_thumb2_insn(env, s, insn))
balrog6a0d8a12008-04-13 13:25:31 +00009818 goto undef32;
pbrook9ee6e8b2007-11-11 00:04:49 +00009819 break;
bellard99c475a2005-01-31 20:45:13 +00009820 }
9821 return;
pbrook9ee6e8b2007-11-11 00:04:49 +00009822undef32:
Peter Maydellbc4a0de2011-01-14 20:39:19 +01009823 gen_exception_insn(s, 4, EXCP_UDEF);
pbrook9ee6e8b2007-11-11 00:04:49 +00009824 return;
9825illegal_op:
bellard99c475a2005-01-31 20:45:13 +00009826undef:
Peter Maydellbc4a0de2011-01-14 20:39:19 +01009827 gen_exception_insn(s, 2, EXCP_UDEF);
bellard99c475a2005-01-31 20:45:13 +00009828}
9829
bellard2c0262a2003-09-30 20:34:21 +00009830/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
9831 basic block 'tb'. If search_pc is TRUE, also generate PC
9832 information for each intermediate instruction. */
ths2cfc5f12008-07-18 18:01:29 +00009833static inline void gen_intermediate_code_internal(CPUState *env,
9834 TranslationBlock *tb,
9835 int search_pc)
bellard2c0262a2003-09-30 20:34:21 +00009836{
9837 DisasContext dc1, *dc = &dc1;
aliguoria1d1bb32008-11-18 20:07:32 +00009838 CPUBreakpoint *bp;
bellard2c0262a2003-09-30 20:34:21 +00009839 uint16_t *gen_opc_end;
9840 int j, lj;
bellard0fa85d42005-01-03 23:43:32 +00009841 target_ulong pc_start;
bellardb5ff1b32005-11-26 10:38:39 +00009842 uint32_t next_page_start;
pbrook2e70f6e2008-06-29 01:03:05 +00009843 int num_insns;
9844 int max_insns;
ths3b46e622007-09-17 08:09:54 +00009845
bellard2c0262a2003-09-30 20:34:21 +00009846 /* generate intermediate code */
bellard0fa85d42005-01-03 23:43:32 +00009847 pc_start = tb->pc;
ths3b46e622007-09-17 08:09:54 +00009848
bellard2c0262a2003-09-30 20:34:21 +00009849 dc->tb = tb;
9850
bellard2c0262a2003-09-30 20:34:21 +00009851 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
bellard2c0262a2003-09-30 20:34:21 +00009852
9853 dc->is_jmp = DISAS_NEXT;
9854 dc->pc = pc_start;
bellard8aaca4c2005-04-23 18:27:52 +00009855 dc->singlestep_enabled = env->singlestep_enabled;
bellarde50e6a22005-04-26 20:36:11 +00009856 dc->condjmp = 0;
Peter Maydell7204ab82011-01-14 20:39:19 +01009857 dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
Peter Maydell98eac7c2011-01-14 20:39:19 +01009858 dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
9859 dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
bellardb5ff1b32005-11-26 10:38:39 +00009860#if !defined(CONFIG_USER_ONLY)
Peter Maydell61f74d62011-01-14 20:39:19 +01009861 dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
bellardb5ff1b32005-11-26 10:38:39 +00009862#endif
Peter Maydell5df8bac2011-01-14 20:39:19 +01009863 dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
Peter Maydell69d1fc22011-01-14 20:39:19 +01009864 dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
9865 dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
pbrooka7812ae2008-11-17 14:43:54 +00009866 cpu_F0s = tcg_temp_new_i32();
9867 cpu_F1s = tcg_temp_new_i32();
9868 cpu_F0d = tcg_temp_new_i64();
9869 cpu_F1d = tcg_temp_new_i64();
pbrookad694712008-03-31 03:48:30 +00009870 cpu_V0 = cpu_F0d;
9871 cpu_V1 = cpu_F1d;
pbrooke6771372008-03-31 03:49:05 +00009872 /* FIXME: cpu_M0 can probably be the same as cpu_V0. */
pbrooka7812ae2008-11-17 14:43:54 +00009873 cpu_M0 = tcg_temp_new_i64();
bellardb5ff1b32005-11-26 10:38:39 +00009874 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
bellard2c0262a2003-09-30 20:34:21 +00009875 lj = -1;
pbrook2e70f6e2008-06-29 01:03:05 +00009876 num_insns = 0;
9877 max_insns = tb->cflags & CF_COUNT_MASK;
9878 if (max_insns == 0)
9879 max_insns = CF_COUNT_MASK;
9880
9881 gen_icount_start();
Peter Maydelle12ce782011-01-14 20:39:19 +01009882
Peter Maydell38499022011-03-06 21:39:55 +00009883 tcg_clear_temp_count();
9884
Peter Maydelle12ce782011-01-14 20:39:19 +01009885 /* A note on handling of the condexec (IT) bits:
9886 *
9887 * We want to avoid the overhead of having to write the updated condexec
9888 * bits back to the CPUState for every instruction in an IT block. So:
9889 * (1) if the condexec bits are not already zero then we write
9890 * zero back into the CPUState now. This avoids complications trying
9891 * to do it at the end of the block. (For example if we don't do this
9892 * it's hard to identify whether we can safely skip writing condexec
9893 * at the end of the TB, which we definitely want to do for the case
9894 * where a TB doesn't do anything with the IT state at all.)
9895 * (2) if we are going to leave the TB then we call gen_set_condexec()
9896 * which will write the correct value into CPUState if zero is wrong.
9897 * This is done both for leaving the TB at the end, and for leaving
9898 * it because of an exception we know will happen, which is done in
9899 * gen_exception_insn(). The latter is necessary because we need to
9900 * leave the TB with the PC/IT state just prior to execution of the
9901 * instruction which caused the exception.
9902 * (3) if we leave the TB unexpectedly (eg a data abort on a load)
9903 * then the CPUState will be wrong and we need to reset it.
9904 * This is handled in the same way as restoration of the
9905 * PC in these situations: we will be called again with search_pc=1
9906 * and generate a mapping of the condexec bits for each PC in
Stefan Weile87b7cb2011-04-18 06:39:52 +00009907 * gen_opc_condexec_bits[]. restore_state_to_opc() then uses
9908 * this to restore the condexec bits.
Peter Maydelle12ce782011-01-14 20:39:19 +01009909 *
9910 * Note that there are no instructions which can read the condexec
9911 * bits, and none which can write non-static values to them, so
9912 * we don't need to care about whether CPUState is correct in the
9913 * middle of a TB.
9914 */
9915
pbrook9ee6e8b2007-11-11 00:04:49 +00009916 /* Reset the conditional execution bits immediately. This avoids
9917 complications trying to do it at the end of the block. */
Peter Maydell98eac7c2011-01-14 20:39:19 +01009918 if (dc->condexec_mask || dc->condexec_cond)
pbrook8f012452008-03-31 03:46:03 +00009919 {
Peter Maydell7d1b0092011-03-06 21:39:54 +00009920 TCGv tmp = tcg_temp_new_i32();
pbrook8f012452008-03-31 03:46:03 +00009921 tcg_gen_movi_i32(tmp, 0);
pbrookd9ba4832008-03-31 03:46:50 +00009922 store_cpu_field(tmp, condexec_bits);
pbrook8f012452008-03-31 03:46:03 +00009923 }
bellard2c0262a2003-09-30 20:34:21 +00009924 do {
pbrookfbb4a2e2008-05-29 00:20:44 +00009925#ifdef CONFIG_USER_ONLY
9926 /* Intercept jump to the magic kernel page. */
9927 if (dc->pc >= 0xffff0000) {
9928 /* We always get here via a jump, so know we are not in a
9929 conditional execution block. */
9930 gen_exception(EXCP_KERNEL_TRAP);
9931 dc->is_jmp = DISAS_UPDATE;
9932 break;
9933 }
9934#else
pbrook9ee6e8b2007-11-11 00:04:49 +00009935 if (dc->pc >= 0xfffffff0 && IS_M(env)) {
9936 /* We always get here via a jump, so know we are not in a
9937 conditional execution block. */
pbrookd9ba4832008-03-31 03:46:50 +00009938 gen_exception(EXCP_EXCEPTION_EXIT);
pbrookd60bb012008-07-11 00:27:19 +00009939 dc->is_jmp = DISAS_UPDATE;
9940 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00009941 }
9942#endif
9943
Blue Swirl72cf2d42009-09-12 07:36:22 +00009944 if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
9945 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
aliguoria1d1bb32008-11-18 20:07:32 +00009946 if (bp->pc == dc->pc) {
Peter Maydellbc4a0de2011-01-14 20:39:19 +01009947 gen_exception_insn(dc, 0, EXCP_DEBUG);
pbrook9ee6e8b2007-11-11 00:04:49 +00009948 /* Advance PC so that clearing the breakpoint will
9949 invalidate this TB. */
9950 dc->pc += 2;
9951 goto done_generating;
bellard1fddef42005-04-17 19:16:13 +00009952 break;
9953 }
9954 }
9955 }
bellard2c0262a2003-09-30 20:34:21 +00009956 if (search_pc) {
9957 j = gen_opc_ptr - gen_opc_buf;
9958 if (lj < j) {
9959 lj++;
9960 while (lj < j)
9961 gen_opc_instr_start[lj++] = 0;
9962 }
bellard0fa85d42005-01-03 23:43:32 +00009963 gen_opc_pc[lj] = dc->pc;
Peter Maydelle12ce782011-01-14 20:39:19 +01009964 gen_opc_condexec_bits[lj] = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1);
bellard2c0262a2003-09-30 20:34:21 +00009965 gen_opc_instr_start[lj] = 1;
pbrook2e70f6e2008-06-29 01:03:05 +00009966 gen_opc_icount[lj] = num_insns;
bellard2c0262a2003-09-30 20:34:21 +00009967 }
bellarde50e6a22005-04-26 20:36:11 +00009968
pbrook2e70f6e2008-06-29 01:03:05 +00009969 if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
9970 gen_io_start();
9971
Peter Maydell56424632011-01-18 13:08:40 +00009972 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
9973 tcg_gen_debug_insn_start(dc->pc);
9974 }
9975
Peter Maydell7204ab82011-01-14 20:39:19 +01009976 if (dc->thumb) {
pbrook9ee6e8b2007-11-11 00:04:49 +00009977 disas_thumb_insn(env, dc);
9978 if (dc->condexec_mask) {
9979 dc->condexec_cond = (dc->condexec_cond & 0xe)
9980 | ((dc->condexec_mask >> 4) & 1);
9981 dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
9982 if (dc->condexec_mask == 0) {
9983 dc->condexec_cond = 0;
9984 }
9985 }
9986 } else {
9987 disas_arm_insn(env, dc);
9988 }
bellarde50e6a22005-04-26 20:36:11 +00009989
9990 if (dc->condjmp && !dc->is_jmp) {
9991 gen_set_label(dc->condlabel);
9992 dc->condjmp = 0;
9993 }
Peter Maydell38499022011-03-06 21:39:55 +00009994
9995 if (tcg_check_temp_count()) {
9996 fprintf(stderr, "TCG temporary leak before %08x\n", dc->pc);
9997 }
9998
balrogaaf2d972008-12-07 13:20:16 +00009999 /* Translation stops when a conditional branch is encountered.
bellarde50e6a22005-04-26 20:36:11 +000010000 * Otherwise the subsequent code could get translated several times.
bellardb5ff1b32005-11-26 10:38:39 +000010001 * Also stop translation when a page boundary is reached. This
thsbf20dc02008-06-30 17:22:19 +000010002 * ensures prefetch aborts occur at the right place. */
pbrook2e70f6e2008-06-29 01:03:05 +000010003 num_insns ++;
bellard1fddef42005-04-17 19:16:13 +000010004 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
10005 !env->singlestep_enabled &&
aurel321b530a62009-04-05 20:08:59 +000010006 !singlestep &&
pbrook2e70f6e2008-06-29 01:03:05 +000010007 dc->pc < next_page_start &&
10008 num_insns < max_insns);
10009
10010 if (tb->cflags & CF_LAST_IO) {
10011 if (dc->condjmp) {
10012 /* FIXME: This can theoretically happen with self-modifying
10013 code. */
10014 cpu_abort(env, "IO on conditional branch instruction");
10015 }
10016 gen_io_end();
10017 }
pbrook9ee6e8b2007-11-11 00:04:49 +000010018
bellardb5ff1b32005-11-26 10:38:39 +000010019 /* At this stage dc->condjmp will only be set when the skipped
pbrook9ee6e8b2007-11-11 00:04:49 +000010020 instruction was a conditional branch or trap, and the PC has
10021 already been written. */
ths551bd272008-07-03 17:57:36 +000010022 if (unlikely(env->singlestep_enabled)) {
bellard8aaca4c2005-04-23 18:27:52 +000010023 /* Make sure the pc is updated, and raise a debug exception. */
bellarde50e6a22005-04-26 20:36:11 +000010024 if (dc->condjmp) {
pbrook9ee6e8b2007-11-11 00:04:49 +000010025 gen_set_condexec(dc);
10026 if (dc->is_jmp == DISAS_SWI) {
pbrookd9ba4832008-03-31 03:46:50 +000010027 gen_exception(EXCP_SWI);
pbrook9ee6e8b2007-11-11 00:04:49 +000010028 } else {
pbrookd9ba4832008-03-31 03:46:50 +000010029 gen_exception(EXCP_DEBUG);
pbrook9ee6e8b2007-11-11 00:04:49 +000010030 }
bellarde50e6a22005-04-26 20:36:11 +000010031 gen_set_label(dc->condlabel);
10032 }
10033 if (dc->condjmp || !dc->is_jmp) {
pbrook5e3f8782008-03-31 03:47:34 +000010034 gen_set_pc_im(dc->pc);
bellarde50e6a22005-04-26 20:36:11 +000010035 dc->condjmp = 0;
bellard8aaca4c2005-04-23 18:27:52 +000010036 }
pbrook9ee6e8b2007-11-11 00:04:49 +000010037 gen_set_condexec(dc);
10038 if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
pbrookd9ba4832008-03-31 03:46:50 +000010039 gen_exception(EXCP_SWI);
pbrook9ee6e8b2007-11-11 00:04:49 +000010040 } else {
10041 /* FIXME: Single stepping a WFI insn will not halt
10042 the CPU. */
pbrookd9ba4832008-03-31 03:46:50 +000010043 gen_exception(EXCP_DEBUG);
pbrook9ee6e8b2007-11-11 00:04:49 +000010044 }
bellard8aaca4c2005-04-23 18:27:52 +000010045 } else {
pbrook9ee6e8b2007-11-11 00:04:49 +000010046 /* While branches must always occur at the end of an IT block,
10047 there are a few other things that can cause us to terminate
10048 the TB in the middel of an IT block:
10049 - Exception generating instructions (bkpt, swi, undefined).
10050 - Page boundaries.
10051 - Hardware watchpoints.
10052 Hardware breakpoints have already been handled and skip this code.
10053 */
10054 gen_set_condexec(dc);
bellard8aaca4c2005-04-23 18:27:52 +000010055 switch(dc->is_jmp) {
bellard8aaca4c2005-04-23 18:27:52 +000010056 case DISAS_NEXT:
bellard6e256c92005-11-20 10:32:05 +000010057 gen_goto_tb(dc, 1, dc->pc);
bellard8aaca4c2005-04-23 18:27:52 +000010058 break;
10059 default:
10060 case DISAS_JUMP:
10061 case DISAS_UPDATE:
10062 /* indicate that the hash table must be used to find the next TB */
bellard57fec1f2008-02-01 10:50:11 +000010063 tcg_gen_exit_tb(0);
bellard8aaca4c2005-04-23 18:27:52 +000010064 break;
10065 case DISAS_TB_JUMP:
10066 /* nothing more to generate */
10067 break;
pbrook9ee6e8b2007-11-11 00:04:49 +000010068 case DISAS_WFI:
pbrookd9ba4832008-03-31 03:46:50 +000010069 gen_helper_wfi();
pbrook9ee6e8b2007-11-11 00:04:49 +000010070 break;
10071 case DISAS_SWI:
pbrookd9ba4832008-03-31 03:46:50 +000010072 gen_exception(EXCP_SWI);
pbrook9ee6e8b2007-11-11 00:04:49 +000010073 break;
bellard8aaca4c2005-04-23 18:27:52 +000010074 }
bellarde50e6a22005-04-26 20:36:11 +000010075 if (dc->condjmp) {
10076 gen_set_label(dc->condlabel);
pbrook9ee6e8b2007-11-11 00:04:49 +000010077 gen_set_condexec(dc);
bellard6e256c92005-11-20 10:32:05 +000010078 gen_goto_tb(dc, 1, dc->pc);
bellarde50e6a22005-04-26 20:36:11 +000010079 dc->condjmp = 0;
10080 }
bellard2c0262a2003-09-30 20:34:21 +000010081 }
pbrook2e70f6e2008-06-29 01:03:05 +000010082
pbrook9ee6e8b2007-11-11 00:04:49 +000010083done_generating:
pbrook2e70f6e2008-06-29 01:03:05 +000010084 gen_icount_end(tb, num_insns);
bellard2c0262a2003-09-30 20:34:21 +000010085 *gen_opc_ptr = INDEX_op_end;
10086
10087#ifdef DEBUG_DISAS
aliguori8fec2b82009-01-15 22:36:53 +000010088 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
aliguori93fcfe32009-01-15 22:34:14 +000010089 qemu_log("----------------\n");
10090 qemu_log("IN: %s\n", lookup_symbol(pc_start));
Peter Maydell7204ab82011-01-14 20:39:19 +010010091 log_target_disas(pc_start, dc->pc - pc_start, dc->thumb);
aliguori93fcfe32009-01-15 22:34:14 +000010092 qemu_log("\n");
bellard2c0262a2003-09-30 20:34:21 +000010093 }
10094#endif
bellardb5ff1b32005-11-26 10:38:39 +000010095 if (search_pc) {
10096 j = gen_opc_ptr - gen_opc_buf;
10097 lj++;
10098 while (lj <= j)
10099 gen_opc_instr_start[lj++] = 0;
bellardb5ff1b32005-11-26 10:38:39 +000010100 } else {
bellard2c0262a2003-09-30 20:34:21 +000010101 tb->size = dc->pc - pc_start;
pbrook2e70f6e2008-06-29 01:03:05 +000010102 tb->icount = num_insns;
bellardb5ff1b32005-11-26 10:38:39 +000010103 }
bellard2c0262a2003-09-30 20:34:21 +000010104}
10105
ths2cfc5f12008-07-18 18:01:29 +000010106void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
bellard2c0262a2003-09-30 20:34:21 +000010107{
ths2cfc5f12008-07-18 18:01:29 +000010108 gen_intermediate_code_internal(env, tb, 0);
bellard2c0262a2003-09-30 20:34:21 +000010109}
10110
ths2cfc5f12008-07-18 18:01:29 +000010111void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
bellard2c0262a2003-09-30 20:34:21 +000010112{
ths2cfc5f12008-07-18 18:01:29 +000010113 gen_intermediate_code_internal(env, tb, 1);
bellard2c0262a2003-09-30 20:34:21 +000010114}
10115
bellardb5ff1b32005-11-26 10:38:39 +000010116static const char *cpu_mode_names[16] = {
10117 "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
10118 "???", "???", "???", "und", "???", "???", "???", "sys"
10119};
pbrook9ee6e8b2007-11-11 00:04:49 +000010120
Stefan Weil9a78eea2010-10-22 23:03:33 +020010121void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
bellard7fe48482004-10-09 18:08:01 +000010122 int flags)
bellard2c0262a2003-09-30 20:34:21 +000010123{
10124 int i;
ths06e80fc2008-07-03 16:40:06 +000010125#if 0
bellardbc380d12005-05-13 22:50:47 +000010126 union {
bellardb7bcbe92005-02-22 19:27:29 +000010127 uint32_t i;
10128 float s;
10129 } s0, s1;
10130 CPU_DoubleU d;
pbrooka94a6ab2006-10-25 17:43:33 +000010131 /* ??? This assumes float64 and double have the same layout.
10132 Oh well, it's only debug dumps. */
10133 union {
10134 float64 f64;
10135 double d;
10136 } d0;
ths06e80fc2008-07-03 16:40:06 +000010137#endif
bellardb5ff1b32005-11-26 10:38:39 +000010138 uint32_t psr;
bellard2c0262a2003-09-30 20:34:21 +000010139
10140 for(i=0;i<16;i++) {
bellard7fe48482004-10-09 18:08:01 +000010141 cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
bellard2c0262a2003-09-30 20:34:21 +000010142 if ((i % 4) == 3)
bellard7fe48482004-10-09 18:08:01 +000010143 cpu_fprintf(f, "\n");
bellard2c0262a2003-09-30 20:34:21 +000010144 else
bellard7fe48482004-10-09 18:08:01 +000010145 cpu_fprintf(f, " ");
bellard2c0262a2003-09-30 20:34:21 +000010146 }
bellardb5ff1b32005-11-26 10:38:39 +000010147 psr = cpsr_read(env);
ths687fa642007-04-02 08:18:36 +000010148 cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
10149 psr,
bellardb5ff1b32005-11-26 10:38:39 +000010150 psr & (1 << 31) ? 'N' : '-',
10151 psr & (1 << 30) ? 'Z' : '-',
10152 psr & (1 << 29) ? 'C' : '-',
10153 psr & (1 << 28) ? 'V' : '-',
ths5fafdf22007-09-16 21:08:06 +000010154 psr & CPSR_T ? 'T' : 'A',
bellardb5ff1b32005-11-26 10:38:39 +000010155 cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
bellardb7bcbe92005-02-22 19:27:29 +000010156
pbrook5e3f8782008-03-31 03:47:34 +000010157#if 0
bellardb7bcbe92005-02-22 19:27:29 +000010158 for (i = 0; i < 16; i++) {
bellard8e960052005-04-07 19:42:46 +000010159 d.d = env->vfp.regs[i];
10160 s0.i = d.l.lower;
10161 s1.i = d.l.upper;
pbrooka94a6ab2006-10-25 17:43:33 +000010162 d0.f64 = d.d;
10163 cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
bellardb7bcbe92005-02-22 19:27:29 +000010164 i * 2, (int)s0.i, s0.s,
pbrooka94a6ab2006-10-25 17:43:33 +000010165 i * 2 + 1, (int)s1.i, s1.s,
bellardb7bcbe92005-02-22 19:27:29 +000010166 i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
pbrooka94a6ab2006-10-25 17:43:33 +000010167 d0.d);
bellardb7bcbe92005-02-22 19:27:29 +000010168 }
pbrook40f137e2006-02-20 00:33:36 +000010169 cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
pbrook5e3f8782008-03-31 03:47:34 +000010170#endif
bellard2c0262a2003-09-30 20:34:21 +000010171}
bellarda6b025d2004-01-24 15:18:16 +000010172
Stefan Weile87b7cb2011-04-18 06:39:52 +000010173void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
aurel32d2856f12008-04-28 00:32:32 +000010174{
10175 env->regs[15] = gen_opc_pc[pc_pos];
Peter Maydelle12ce782011-01-14 20:39:19 +010010176 env->condexec_bits = gen_opc_condexec_bits[pc_pos];
aurel32d2856f12008-04-28 00:32:32 +000010177}