blob: da4063ba376e1c52427c4e267be5ab4dc9b0cea3 [file] [log] [blame]
Alexander Graf14ade102013-09-03 20:12:10 +01001/*
2 * AArch64 translation
3 *
4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19#include <stdarg.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <inttypes.h>
24
25#include "cpu.h"
26#include "tcg-op.h"
27#include "qemu/log.h"
28#include "translate.h"
29#include "qemu/host-utils.h"
30
Peter Maydell40f860c2013-12-17 19:42:31 +000031#include "exec/gen-icount.h"
32
Alexander Graf14ade102013-09-03 20:12:10 +010033#include "helper.h"
34#define GEN_HELPER 1
35#include "helper.h"
36
37static TCGv_i64 cpu_X[32];
38static TCGv_i64 cpu_pc;
Alexander Graf832ffa12013-12-17 19:42:34 +000039static TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
Alexander Graf14ade102013-09-03 20:12:10 +010040
Michael Matzfa2ef212014-01-04 22:15:47 +000041/* Load/store exclusive handling */
42static TCGv_i64 cpu_exclusive_addr;
43static TCGv_i64 cpu_exclusive_val;
44static TCGv_i64 cpu_exclusive_high;
45#ifdef CONFIG_USER_ONLY
46static TCGv_i64 cpu_exclusive_test;
47static TCGv_i32 cpu_exclusive_info;
48#endif
49
Alexander Graf14ade102013-09-03 20:12:10 +010050static const char *regnames[] = {
51 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
52 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
53 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
54 "x24", "x25", "x26", "x27", "x28", "x29", "lr", "sp"
55};
56
Alexander Graf832ffa12013-12-17 19:42:34 +000057enum a64_shift_type {
58 A64_SHIFT_TYPE_LSL = 0,
59 A64_SHIFT_TYPE_LSR = 1,
60 A64_SHIFT_TYPE_ASR = 2,
61 A64_SHIFT_TYPE_ROR = 3
62};
63
Alex Bennée384b26f2014-01-31 14:47:30 +000064/* Table based decoder typedefs - used when the relevant bits for decode
65 * are too awkwardly scattered across the instruction (eg SIMD).
66 */
67typedef void AArch64DecodeFn(DisasContext *s, uint32_t insn);
68
69typedef struct AArch64DecodeTable {
70 uint32_t pattern;
71 uint32_t mask;
72 AArch64DecodeFn *disas_fn;
73} AArch64DecodeTable;
74
Peter Maydell1f8a73a2014-01-31 14:47:37 +000075/* Function prototype for gen_ functions for calling Neon helpers */
76typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32);
Peter Maydell6d9571f2014-02-08 14:46:55 +000077typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32);
Peter Maydell70d7f982014-02-20 10:35:55 +000078typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64);
Peter Maydelld980fd52014-02-03 23:31:52 +000079typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);
80typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64);
Peter Maydell70d7f982014-02-20 10:35:55 +000081typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32);
Alex Bennée8908f4d2014-02-20 10:35:49 +000082typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
83typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
Peter Maydell1f8a73a2014-01-31 14:47:37 +000084
Alexander Graf14ade102013-09-03 20:12:10 +010085/* initialize TCG globals. */
86void a64_translate_init(void)
87{
88 int i;
89
90 cpu_pc = tcg_global_mem_new_i64(TCG_AREG0,
91 offsetof(CPUARMState, pc),
92 "pc");
93 for (i = 0; i < 32; i++) {
94 cpu_X[i] = tcg_global_mem_new_i64(TCG_AREG0,
95 offsetof(CPUARMState, xregs[i]),
96 regnames[i]);
97 }
98
Alexander Graf832ffa12013-12-17 19:42:34 +000099 cpu_NF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, NF), "NF");
100 cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF");
101 cpu_CF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, CF), "CF");
102 cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF");
Michael Matzfa2ef212014-01-04 22:15:47 +0000103
104 cpu_exclusive_addr = tcg_global_mem_new_i64(TCG_AREG0,
105 offsetof(CPUARMState, exclusive_addr), "exclusive_addr");
106 cpu_exclusive_val = tcg_global_mem_new_i64(TCG_AREG0,
107 offsetof(CPUARMState, exclusive_val), "exclusive_val");
108 cpu_exclusive_high = tcg_global_mem_new_i64(TCG_AREG0,
109 offsetof(CPUARMState, exclusive_high), "exclusive_high");
110#ifdef CONFIG_USER_ONLY
111 cpu_exclusive_test = tcg_global_mem_new_i64(TCG_AREG0,
112 offsetof(CPUARMState, exclusive_test), "exclusive_test");
113 cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
114 offsetof(CPUARMState, exclusive_info), "exclusive_info");
115#endif
Alexander Graf14ade102013-09-03 20:12:10 +0100116}
117
118void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
119 fprintf_function cpu_fprintf, int flags)
120{
121 ARMCPU *cpu = ARM_CPU(cs);
122 CPUARMState *env = &cpu->env;
Peter Maydelld3563122013-12-17 19:42:30 +0000123 uint32_t psr = pstate_read(env);
Alexander Graf14ade102013-09-03 20:12:10 +0100124 int i;
125
126 cpu_fprintf(f, "PC=%016"PRIx64" SP=%016"PRIx64"\n",
127 env->pc, env->xregs[31]);
128 for (i = 0; i < 31; i++) {
129 cpu_fprintf(f, "X%02d=%016"PRIx64, i, env->xregs[i]);
130 if ((i % 4) == 3) {
131 cpu_fprintf(f, "\n");
132 } else {
133 cpu_fprintf(f, " ");
134 }
135 }
Peter Maydelld3563122013-12-17 19:42:30 +0000136 cpu_fprintf(f, "PSTATE=%08x (flags %c%c%c%c)\n",
137 psr,
138 psr & PSTATE_N ? 'N' : '-',
139 psr & PSTATE_Z ? 'Z' : '-',
140 psr & PSTATE_C ? 'C' : '-',
141 psr & PSTATE_V ? 'V' : '-');
Alexander Graf14ade102013-09-03 20:12:10 +0100142 cpu_fprintf(f, "\n");
Alexander Graff6d8a312014-01-04 22:15:49 +0000143
144 if (flags & CPU_DUMP_FPU) {
145 int numvfpregs = 32;
146 for (i = 0; i < numvfpregs; i += 2) {
147 uint64_t vlo = float64_val(env->vfp.regs[i * 2]);
148 uint64_t vhi = float64_val(env->vfp.regs[(i * 2) + 1]);
149 cpu_fprintf(f, "q%02d=%016" PRIx64 ":%016" PRIx64 " ",
150 i, vhi, vlo);
151 vlo = float64_val(env->vfp.regs[(i + 1) * 2]);
152 vhi = float64_val(env->vfp.regs[((i + 1) * 2) + 1]);
153 cpu_fprintf(f, "q%02d=%016" PRIx64 ":%016" PRIx64 "\n",
154 i + 1, vhi, vlo);
155 }
156 cpu_fprintf(f, "FPCR: %08x FPSR: %08x\n",
157 vfp_get_fpcr(env), vfp_get_fpsr(env));
158 }
Alexander Graf14ade102013-09-03 20:12:10 +0100159}
160
Peter Maydell4a08d472013-12-22 22:32:27 +0000161static int get_mem_index(DisasContext *s)
162{
163#ifdef CONFIG_USER_ONLY
164 return 1;
165#else
166 return s->user;
167#endif
168}
169
Alexander Graf14ade102013-09-03 20:12:10 +0100170void gen_a64_set_pc_im(uint64_t val)
171{
172 tcg_gen_movi_i64(cpu_pc, val);
173}
174
175static void gen_exception(int excp)
176{
177 TCGv_i32 tmp = tcg_temp_new_i32();
178 tcg_gen_movi_i32(tmp, excp);
179 gen_helper_exception(cpu_env, tmp);
180 tcg_temp_free_i32(tmp);
181}
182
183static void gen_exception_insn(DisasContext *s, int offset, int excp)
184{
185 gen_a64_set_pc_im(s->pc - offset);
186 gen_exception(excp);
Peter Maydell40f860c2013-12-17 19:42:31 +0000187 s->is_jmp = DISAS_EXC;
188}
189
190static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
191{
192 /* No direct tb linking with singlestep or deterministic io */
193 if (s->singlestep_enabled || (s->tb->cflags & CF_LAST_IO)) {
194 return false;
195 }
196
197 /* Only link tbs from inside the same guest page */
198 if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
199 return false;
200 }
201
202 return true;
203}
204
205static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
206{
207 TranslationBlock *tb;
208
209 tb = s->tb;
210 if (use_goto_tb(s, n, dest)) {
211 tcg_gen_goto_tb(n);
212 gen_a64_set_pc_im(dest);
213 tcg_gen_exit_tb((tcg_target_long)tb + n);
214 s->is_jmp = DISAS_TB_JUMP;
215 } else {
216 gen_a64_set_pc_im(dest);
217 if (s->singlestep_enabled) {
218 gen_exception(EXCP_DEBUG);
219 }
220 tcg_gen_exit_tb(0);
221 s->is_jmp = DISAS_JUMP;
222 }
Alexander Graf14ade102013-09-03 20:12:10 +0100223}
224
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000225static void unallocated_encoding(DisasContext *s)
Alexander Graf14ade102013-09-03 20:12:10 +0100226{
Alexander Graf14ade102013-09-03 20:12:10 +0100227 gen_exception_insn(s, 4, EXCP_UDEF);
228}
229
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000230#define unsupported_encoding(s, insn) \
231 do { \
232 qemu_log_mask(LOG_UNIMP, \
233 "%s:%d: unsupported instruction encoding 0x%08x " \
234 "at pc=%016" PRIx64 "\n", \
235 __FILE__, __LINE__, insn, s->pc - 4); \
236 unallocated_encoding(s); \
237 } while (0);
Alexander Graf14ade102013-09-03 20:12:10 +0100238
Alexander Graf11e169d2013-12-17 19:42:32 +0000239static void init_tmp_a64_array(DisasContext *s)
240{
241#ifdef CONFIG_DEBUG_TCG
242 int i;
243 for (i = 0; i < ARRAY_SIZE(s->tmp_a64); i++) {
244 TCGV_UNUSED_I64(s->tmp_a64[i]);
245 }
246#endif
247 s->tmp_a64_count = 0;
248}
249
250static void free_tmp_a64(DisasContext *s)
251{
252 int i;
253 for (i = 0; i < s->tmp_a64_count; i++) {
254 tcg_temp_free_i64(s->tmp_a64[i]);
255 }
256 init_tmp_a64_array(s);
257}
258
259static TCGv_i64 new_tmp_a64(DisasContext *s)
260{
261 assert(s->tmp_a64_count < TMP_A64_MAX);
262 return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64();
263}
264
265static TCGv_i64 new_tmp_a64_zero(DisasContext *s)
266{
267 TCGv_i64 t = new_tmp_a64(s);
268 tcg_gen_movi_i64(t, 0);
269 return t;
270}
271
Alexander Graf71b46082013-12-17 19:42:36 +0000272/*
273 * Register access functions
274 *
275 * These functions are used for directly accessing a register in where
276 * changes to the final register value are likely to be made. If you
277 * need to use a register for temporary calculation (e.g. index type
278 * operations) use the read_* form.
279 *
280 * B1.2.1 Register mappings
281 *
282 * In instruction register encoding 31 can refer to ZR (zero register) or
283 * the SP (stack pointer) depending on context. In QEMU's case we map SP
284 * to cpu_X[31] and ZR accesses to a temporary which can be discarded.
285 * This is the point of the _sp forms.
286 */
Alexander Graf11e169d2013-12-17 19:42:32 +0000287static TCGv_i64 cpu_reg(DisasContext *s, int reg)
288{
289 if (reg == 31) {
290 return new_tmp_a64_zero(s);
291 } else {
292 return cpu_X[reg];
293 }
294}
295
Alexander Graf71b46082013-12-17 19:42:36 +0000296/* register access for when 31 == SP */
297static TCGv_i64 cpu_reg_sp(DisasContext *s, int reg)
298{
299 return cpu_X[reg];
300}
301
Alexander Graf60e53382013-12-17 19:42:33 +0000302/* read a cpu register in 32bit/64bit mode. Returns a TCGv_i64
303 * representing the register contents. This TCGv is an auto-freed
304 * temporary so it need not be explicitly freed, and may be modified.
305 */
306static TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
307{
308 TCGv_i64 v = new_tmp_a64(s);
309 if (reg != 31) {
310 if (sf) {
311 tcg_gen_mov_i64(v, cpu_X[reg]);
312 } else {
313 tcg_gen_ext32u_i64(v, cpu_X[reg]);
314 }
315 } else {
316 tcg_gen_movi_i64(v, 0);
317 }
318 return v;
319}
320
Peter Maydell4a08d472013-12-22 22:32:27 +0000321static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
322{
323 TCGv_i64 v = new_tmp_a64(s);
324 if (sf) {
325 tcg_gen_mov_i64(v, cpu_X[reg]);
326 } else {
327 tcg_gen_ext32u_i64(v, cpu_X[reg]);
328 }
329 return v;
330}
331
Alex Bennée72430bf2014-01-31 14:47:30 +0000332/* Return the offset into CPUARMState of an element of specified
333 * size, 'element' places in from the least significant end of
334 * the FP/vector register Qn.
335 */
336static inline int vec_reg_offset(int regno, int element, TCGMemOp size)
337{
338 int offs = offsetof(CPUARMState, vfp.regs[regno * 2]);
339#ifdef HOST_WORDS_BIGENDIAN
340 /* This is complicated slightly because vfp.regs[2n] is
341 * still the low half and vfp.regs[2n+1] the high half
342 * of the 128 bit vector, even on big endian systems.
343 * Calculate the offset assuming a fully bigendian 128 bits,
344 * then XOR to account for the order of the two 64 bit halves.
345 */
346 offs += (16 - ((element + 1) * (1 << size)));
347 offs ^= 8;
348#else
349 offs += element * (1 << size);
350#endif
351 return offs;
352}
353
Peter Maydelle2f90562014-01-04 22:15:49 +0000354/* Return the offset into CPUARMState of a slice (from
355 * the least significant end) of FP register Qn (ie
356 * Dn, Sn, Hn or Bn).
357 * (Note that this is not the same mapping as for A32; see cpu.h)
358 */
359static inline int fp_reg_offset(int regno, TCGMemOp size)
360{
361 int offs = offsetof(CPUARMState, vfp.regs[regno * 2]);
362#ifdef HOST_WORDS_BIGENDIAN
363 offs += (8 - (1 << size));
364#endif
365 return offs;
366}
367
368/* Offset of the high half of the 128 bit vector Qn */
369static inline int fp_reg_hi_offset(int regno)
370{
371 return offsetof(CPUARMState, vfp.regs[regno * 2 + 1]);
372}
373
Alexander Grafec73d2e2014-01-04 22:15:50 +0000374/* Convenience accessors for reading and writing single and double
375 * FP registers. Writing clears the upper parts of the associated
376 * 128 bit vector register, as required by the architecture.
377 * Note that unlike the GP register accessors, the values returned
378 * by the read functions must be manually freed.
379 */
380static TCGv_i64 read_fp_dreg(DisasContext *s, int reg)
381{
382 TCGv_i64 v = tcg_temp_new_i64();
383
384 tcg_gen_ld_i64(v, cpu_env, fp_reg_offset(reg, MO_64));
385 return v;
386}
387
388static TCGv_i32 read_fp_sreg(DisasContext *s, int reg)
389{
390 TCGv_i32 v = tcg_temp_new_i32();
391
392 tcg_gen_ld_i32(v, cpu_env, fp_reg_offset(reg, MO_32));
393 return v;
394}
395
396static void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v)
397{
398 TCGv_i64 tcg_zero = tcg_const_i64(0);
399
400 tcg_gen_st_i64(v, cpu_env, fp_reg_offset(reg, MO_64));
401 tcg_gen_st_i64(tcg_zero, cpu_env, fp_reg_hi_offset(reg));
402 tcg_temp_free_i64(tcg_zero);
403}
404
405static void write_fp_sreg(DisasContext *s, int reg, TCGv_i32 v)
406{
407 TCGv_i64 tmp = tcg_temp_new_i64();
408
409 tcg_gen_extu_i32_i64(tmp, v);
410 write_fp_dreg(s, reg, tmp);
411 tcg_temp_free_i64(tmp);
412}
413
414static TCGv_ptr get_fpstatus_ptr(void)
415{
416 TCGv_ptr statusptr = tcg_temp_new_ptr();
417 int offset;
418
419 /* In A64 all instructions (both FP and Neon) use the FPCR;
420 * there is no equivalent of the A32 Neon "standard FPSCR value"
421 * and all operations use vfp.fp_status.
422 */
423 offset = offsetof(CPUARMState, vfp.fp_status);
424 tcg_gen_addi_ptr(statusptr, cpu_env, offset);
425 return statusptr;
426}
427
Alexander Graf832ffa12013-12-17 19:42:34 +0000428/* Set ZF and NF based on a 64 bit result. This is alas fiddlier
429 * than the 32 bit equivalent.
430 */
431static inline void gen_set_NZ64(TCGv_i64 result)
432{
433 TCGv_i64 flag = tcg_temp_new_i64();
434
435 tcg_gen_setcondi_i64(TCG_COND_NE, flag, result, 0);
436 tcg_gen_trunc_i64_i32(cpu_ZF, flag);
437 tcg_gen_shri_i64(flag, result, 32);
438 tcg_gen_trunc_i64_i32(cpu_NF, flag);
439 tcg_temp_free_i64(flag);
440}
441
442/* Set NZCV as for a logical operation: NZ as per result, CV cleared. */
443static inline void gen_logic_CC(int sf, TCGv_i64 result)
444{
445 if (sf) {
446 gen_set_NZ64(result);
447 } else {
448 tcg_gen_trunc_i64_i32(cpu_ZF, result);
449 tcg_gen_trunc_i64_i32(cpu_NF, result);
450 }
451 tcg_gen_movi_i32(cpu_CF, 0);
452 tcg_gen_movi_i32(cpu_VF, 0);
453}
454
Alex Bennéeb0ff21b2013-12-23 23:27:29 +0000455/* dest = T0 + T1; compute C, N, V and Z flags */
456static void gen_add_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
457{
458 if (sf) {
459 TCGv_i64 result, flag, tmp;
460 result = tcg_temp_new_i64();
461 flag = tcg_temp_new_i64();
462 tmp = tcg_temp_new_i64();
463
464 tcg_gen_movi_i64(tmp, 0);
465 tcg_gen_add2_i64(result, flag, t0, tmp, t1, tmp);
466
467 tcg_gen_trunc_i64_i32(cpu_CF, flag);
468
469 gen_set_NZ64(result);
470
471 tcg_gen_xor_i64(flag, result, t0);
472 tcg_gen_xor_i64(tmp, t0, t1);
473 tcg_gen_andc_i64(flag, flag, tmp);
474 tcg_temp_free_i64(tmp);
475 tcg_gen_shri_i64(flag, flag, 32);
476 tcg_gen_trunc_i64_i32(cpu_VF, flag);
477
478 tcg_gen_mov_i64(dest, result);
479 tcg_temp_free_i64(result);
480 tcg_temp_free_i64(flag);
481 } else {
482 /* 32 bit arithmetic */
483 TCGv_i32 t0_32 = tcg_temp_new_i32();
484 TCGv_i32 t1_32 = tcg_temp_new_i32();
485 TCGv_i32 tmp = tcg_temp_new_i32();
486
487 tcg_gen_movi_i32(tmp, 0);
488 tcg_gen_trunc_i64_i32(t0_32, t0);
489 tcg_gen_trunc_i64_i32(t1_32, t1);
490 tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, t1_32, tmp);
491 tcg_gen_mov_i32(cpu_ZF, cpu_NF);
492 tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
493 tcg_gen_xor_i32(tmp, t0_32, t1_32);
494 tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
495 tcg_gen_extu_i32_i64(dest, cpu_NF);
496
497 tcg_temp_free_i32(tmp);
498 tcg_temp_free_i32(t0_32);
499 tcg_temp_free_i32(t1_32);
500 }
501}
502
503/* dest = T0 - T1; compute C, N, V and Z flags */
504static void gen_sub_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
505{
506 if (sf) {
507 /* 64 bit arithmetic */
508 TCGv_i64 result, flag, tmp;
509
510 result = tcg_temp_new_i64();
511 flag = tcg_temp_new_i64();
512 tcg_gen_sub_i64(result, t0, t1);
513
514 gen_set_NZ64(result);
515
516 tcg_gen_setcond_i64(TCG_COND_GEU, flag, t0, t1);
517 tcg_gen_trunc_i64_i32(cpu_CF, flag);
518
519 tcg_gen_xor_i64(flag, result, t0);
520 tmp = tcg_temp_new_i64();
521 tcg_gen_xor_i64(tmp, t0, t1);
522 tcg_gen_and_i64(flag, flag, tmp);
523 tcg_temp_free_i64(tmp);
524 tcg_gen_shri_i64(flag, flag, 32);
525 tcg_gen_trunc_i64_i32(cpu_VF, flag);
526 tcg_gen_mov_i64(dest, result);
527 tcg_temp_free_i64(flag);
528 tcg_temp_free_i64(result);
529 } else {
530 /* 32 bit arithmetic */
531 TCGv_i32 t0_32 = tcg_temp_new_i32();
532 TCGv_i32 t1_32 = tcg_temp_new_i32();
533 TCGv_i32 tmp;
534
535 tcg_gen_trunc_i64_i32(t0_32, t0);
536 tcg_gen_trunc_i64_i32(t1_32, t1);
537 tcg_gen_sub_i32(cpu_NF, t0_32, t1_32);
538 tcg_gen_mov_i32(cpu_ZF, cpu_NF);
539 tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0_32, t1_32);
540 tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
541 tmp = tcg_temp_new_i32();
542 tcg_gen_xor_i32(tmp, t0_32, t1_32);
543 tcg_temp_free_i32(t0_32);
544 tcg_temp_free_i32(t1_32);
545 tcg_gen_and_i32(cpu_VF, cpu_VF, tmp);
546 tcg_temp_free_i32(tmp);
547 tcg_gen_extu_i32_i64(dest, cpu_NF);
548 }
549}
550
Claudio Fontana643dbb02014-01-04 22:15:46 +0000551/* dest = T0 + T1 + CF; do not compute flags. */
552static void gen_adc(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
553{
554 TCGv_i64 flag = tcg_temp_new_i64();
555 tcg_gen_extu_i32_i64(flag, cpu_CF);
556 tcg_gen_add_i64(dest, t0, t1);
557 tcg_gen_add_i64(dest, dest, flag);
558 tcg_temp_free_i64(flag);
559
560 if (!sf) {
561 tcg_gen_ext32u_i64(dest, dest);
562 }
563}
564
565/* dest = T0 + T1 + CF; compute C, N, V and Z flags. */
566static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
567{
568 if (sf) {
569 TCGv_i64 result, cf_64, vf_64, tmp;
570 result = tcg_temp_new_i64();
571 cf_64 = tcg_temp_new_i64();
572 vf_64 = tcg_temp_new_i64();
573 tmp = tcg_const_i64(0);
574
575 tcg_gen_extu_i32_i64(cf_64, cpu_CF);
576 tcg_gen_add2_i64(result, cf_64, t0, tmp, cf_64, tmp);
577 tcg_gen_add2_i64(result, cf_64, result, cf_64, t1, tmp);
578 tcg_gen_trunc_i64_i32(cpu_CF, cf_64);
579 gen_set_NZ64(result);
580
581 tcg_gen_xor_i64(vf_64, result, t0);
582 tcg_gen_xor_i64(tmp, t0, t1);
583 tcg_gen_andc_i64(vf_64, vf_64, tmp);
584 tcg_gen_shri_i64(vf_64, vf_64, 32);
585 tcg_gen_trunc_i64_i32(cpu_VF, vf_64);
586
587 tcg_gen_mov_i64(dest, result);
588
589 tcg_temp_free_i64(tmp);
590 tcg_temp_free_i64(vf_64);
591 tcg_temp_free_i64(cf_64);
592 tcg_temp_free_i64(result);
593 } else {
594 TCGv_i32 t0_32, t1_32, tmp;
595 t0_32 = tcg_temp_new_i32();
596 t1_32 = tcg_temp_new_i32();
597 tmp = tcg_const_i32(0);
598
599 tcg_gen_trunc_i64_i32(t0_32, t0);
600 tcg_gen_trunc_i64_i32(t1_32, t1);
601 tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, cpu_CF, tmp);
602 tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1_32, tmp);
603
604 tcg_gen_mov_i32(cpu_ZF, cpu_NF);
605 tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
606 tcg_gen_xor_i32(tmp, t0_32, t1_32);
607 tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
608 tcg_gen_extu_i32_i64(dest, cpu_NF);
609
610 tcg_temp_free_i32(tmp);
611 tcg_temp_free_i32(t1_32);
612 tcg_temp_free_i32(t0_32);
613 }
614}
615
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000616/*
Peter Maydell4a08d472013-12-22 22:32:27 +0000617 * Load/Store generators
618 */
619
620/*
Peter Maydell60510ae2014-02-20 10:35:56 +0000621 * Store from GPR register to memory.
Peter Maydell4a08d472013-12-22 22:32:27 +0000622 */
Peter Maydell60510ae2014-02-20 10:35:56 +0000623static void do_gpr_st_memidx(DisasContext *s, TCGv_i64 source,
624 TCGv_i64 tcg_addr, int size, int memidx)
625{
626 g_assert(size <= 3);
627 tcg_gen_qemu_st_i64(source, tcg_addr, memidx, MO_TE + size);
628}
629
Peter Maydell4a08d472013-12-22 22:32:27 +0000630static void do_gpr_st(DisasContext *s, TCGv_i64 source,
631 TCGv_i64 tcg_addr, int size)
632{
Peter Maydell60510ae2014-02-20 10:35:56 +0000633 do_gpr_st_memidx(s, source, tcg_addr, size, get_mem_index(s));
Peter Maydell4a08d472013-12-22 22:32:27 +0000634}
635
636/*
637 * Load from memory to GPR register
638 */
Peter Maydell60510ae2014-02-20 10:35:56 +0000639static void do_gpr_ld_memidx(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
640 int size, bool is_signed, bool extend, int memidx)
Peter Maydell4a08d472013-12-22 22:32:27 +0000641{
642 TCGMemOp memop = MO_TE + size;
643
644 g_assert(size <= 3);
645
646 if (is_signed) {
647 memop += MO_SIGN;
648 }
649
Peter Maydell60510ae2014-02-20 10:35:56 +0000650 tcg_gen_qemu_ld_i64(dest, tcg_addr, memidx, memop);
Peter Maydell4a08d472013-12-22 22:32:27 +0000651
652 if (extend && is_signed) {
653 g_assert(size < 3);
654 tcg_gen_ext32u_i64(dest, dest);
655 }
656}
657
Peter Maydell60510ae2014-02-20 10:35:56 +0000658static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
659 int size, bool is_signed, bool extend)
660{
661 do_gpr_ld_memidx(s, dest, tcg_addr, size, is_signed, extend,
662 get_mem_index(s));
663}
664
Peter Maydell4a08d472013-12-22 22:32:27 +0000665/*
666 * Store from FP register to memory
667 */
668static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
669{
670 /* This writes the bottom N bits of a 128 bit wide vector to memory */
Peter Maydell4a08d472013-12-22 22:32:27 +0000671 TCGv_i64 tmp = tcg_temp_new_i64();
Peter Maydelle2f90562014-01-04 22:15:49 +0000672 tcg_gen_ld_i64(tmp, cpu_env, fp_reg_offset(srcidx, MO_64));
Peter Maydell4a08d472013-12-22 22:32:27 +0000673 if (size < 4) {
Peter Maydell4a08d472013-12-22 22:32:27 +0000674 tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TE + size);
675 } else {
676 TCGv_i64 tcg_hiaddr = tcg_temp_new_i64();
Peter Maydell4a08d472013-12-22 22:32:27 +0000677 tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TEQ);
678 tcg_gen_qemu_st64(tmp, tcg_addr, get_mem_index(s));
Peter Maydelle2f90562014-01-04 22:15:49 +0000679 tcg_gen_ld_i64(tmp, cpu_env, fp_reg_hi_offset(srcidx));
Peter Maydell4a08d472013-12-22 22:32:27 +0000680 tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
681 tcg_gen_qemu_st_i64(tmp, tcg_hiaddr, get_mem_index(s), MO_TEQ);
682 tcg_temp_free_i64(tcg_hiaddr);
683 }
684
685 tcg_temp_free_i64(tmp);
686}
687
688/*
689 * Load from memory to FP register
690 */
691static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
692{
693 /* This always zero-extends and writes to a full 128 bit wide vector */
Peter Maydell4a08d472013-12-22 22:32:27 +0000694 TCGv_i64 tmplo = tcg_temp_new_i64();
695 TCGv_i64 tmphi;
696
697 if (size < 4) {
698 TCGMemOp memop = MO_TE + size;
699 tmphi = tcg_const_i64(0);
700 tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop);
701 } else {
702 TCGv_i64 tcg_hiaddr;
703 tmphi = tcg_temp_new_i64();
704 tcg_hiaddr = tcg_temp_new_i64();
705
706 tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), MO_TEQ);
707 tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
708 tcg_gen_qemu_ld_i64(tmphi, tcg_hiaddr, get_mem_index(s), MO_TEQ);
709 tcg_temp_free_i64(tcg_hiaddr);
710 }
711
Peter Maydelle2f90562014-01-04 22:15:49 +0000712 tcg_gen_st_i64(tmplo, cpu_env, fp_reg_offset(destidx, MO_64));
713 tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(destidx));
Peter Maydell4a08d472013-12-22 22:32:27 +0000714
715 tcg_temp_free_i64(tmplo);
716 tcg_temp_free_i64(tmphi);
717}
718
Alex Bennée229b7a02013-12-23 23:27:29 +0000719/*
Alex Bennée72430bf2014-01-31 14:47:30 +0000720 * Vector load/store helpers.
721 *
722 * The principal difference between this and a FP load is that we don't
723 * zero extend as we are filling a partial chunk of the vector register.
724 * These functions don't support 128 bit loads/stores, which would be
725 * normal load/store operations.
Peter Maydella08582f2014-01-31 14:47:36 +0000726 *
727 * The _i32 versions are useful when operating on 32 bit quantities
728 * (eg for floating point single or using Neon helper functions).
Alex Bennée72430bf2014-01-31 14:47:30 +0000729 */
730
731/* Get value of an element within a vector register */
732static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
733 int element, TCGMemOp memop)
734{
735 int vect_off = vec_reg_offset(srcidx, element, memop & MO_SIZE);
736 switch (memop) {
737 case MO_8:
738 tcg_gen_ld8u_i64(tcg_dest, cpu_env, vect_off);
739 break;
740 case MO_16:
741 tcg_gen_ld16u_i64(tcg_dest, cpu_env, vect_off);
742 break;
743 case MO_32:
744 tcg_gen_ld32u_i64(tcg_dest, cpu_env, vect_off);
745 break;
746 case MO_8|MO_SIGN:
747 tcg_gen_ld8s_i64(tcg_dest, cpu_env, vect_off);
748 break;
749 case MO_16|MO_SIGN:
750 tcg_gen_ld16s_i64(tcg_dest, cpu_env, vect_off);
751 break;
752 case MO_32|MO_SIGN:
753 tcg_gen_ld32s_i64(tcg_dest, cpu_env, vect_off);
754 break;
755 case MO_64:
756 case MO_64|MO_SIGN:
757 tcg_gen_ld_i64(tcg_dest, cpu_env, vect_off);
758 break;
759 default:
760 g_assert_not_reached();
761 }
762}
763
Peter Maydella08582f2014-01-31 14:47:36 +0000764static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx,
765 int element, TCGMemOp memop)
766{
767 int vect_off = vec_reg_offset(srcidx, element, memop & MO_SIZE);
768 switch (memop) {
769 case MO_8:
770 tcg_gen_ld8u_i32(tcg_dest, cpu_env, vect_off);
771 break;
772 case MO_16:
773 tcg_gen_ld16u_i32(tcg_dest, cpu_env, vect_off);
774 break;
775 case MO_8|MO_SIGN:
776 tcg_gen_ld8s_i32(tcg_dest, cpu_env, vect_off);
777 break;
778 case MO_16|MO_SIGN:
779 tcg_gen_ld16s_i32(tcg_dest, cpu_env, vect_off);
780 break;
781 case MO_32:
782 case MO_32|MO_SIGN:
783 tcg_gen_ld_i32(tcg_dest, cpu_env, vect_off);
784 break;
785 default:
786 g_assert_not_reached();
787 }
788}
789
Alex Bennée72430bf2014-01-31 14:47:30 +0000790/* Set value of an element within a vector register */
791static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
792 int element, TCGMemOp memop)
793{
794 int vect_off = vec_reg_offset(destidx, element, memop & MO_SIZE);
795 switch (memop) {
796 case MO_8:
797 tcg_gen_st8_i64(tcg_src, cpu_env, vect_off);
798 break;
799 case MO_16:
800 tcg_gen_st16_i64(tcg_src, cpu_env, vect_off);
801 break;
802 case MO_32:
803 tcg_gen_st32_i64(tcg_src, cpu_env, vect_off);
804 break;
805 case MO_64:
806 tcg_gen_st_i64(tcg_src, cpu_env, vect_off);
807 break;
808 default:
809 g_assert_not_reached();
810 }
811}
812
Peter Maydell1f8a73a2014-01-31 14:47:37 +0000813static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src,
814 int destidx, int element, TCGMemOp memop)
815{
816 int vect_off = vec_reg_offset(destidx, element, memop & MO_SIZE);
817 switch (memop) {
818 case MO_8:
819 tcg_gen_st8_i32(tcg_src, cpu_env, vect_off);
820 break;
821 case MO_16:
822 tcg_gen_st16_i32(tcg_src, cpu_env, vect_off);
823 break;
824 case MO_32:
825 tcg_gen_st_i32(tcg_src, cpu_env, vect_off);
826 break;
827 default:
828 g_assert_not_reached();
829 }
830}
831
Alex Bennée72430bf2014-01-31 14:47:30 +0000832/* Clear the high 64 bits of a 128 bit vector (in general non-quad
833 * vector ops all need to do this).
834 */
835static void clear_vec_high(DisasContext *s, int rd)
836{
837 TCGv_i64 tcg_zero = tcg_const_i64(0);
838
839 write_vec_element(s, tcg_zero, rd, 1, MO_64);
840 tcg_temp_free_i64(tcg_zero);
841}
842
843/* Store from vector register to memory */
844static void do_vec_st(DisasContext *s, int srcidx, int element,
845 TCGv_i64 tcg_addr, int size)
846{
847 TCGMemOp memop = MO_TE + size;
848 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
849
850 read_vec_element(s, tcg_tmp, srcidx, element, size);
851 tcg_gen_qemu_st_i64(tcg_tmp, tcg_addr, get_mem_index(s), memop);
852
853 tcg_temp_free_i64(tcg_tmp);
854}
855
856/* Load from memory to vector register */
857static void do_vec_ld(DisasContext *s, int destidx, int element,
858 TCGv_i64 tcg_addr, int size)
859{
860 TCGMemOp memop = MO_TE + size;
861 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
862
863 tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr, get_mem_index(s), memop);
864 write_vec_element(s, tcg_tmp, destidx, element, size);
865
866 tcg_temp_free_i64(tcg_tmp);
867}
868
869/*
Alex Bennée229b7a02013-12-23 23:27:29 +0000870 * This utility function is for doing register extension with an
871 * optional shift. You will likely want to pass a temporary for the
872 * destination register. See DecodeRegExtend() in the ARM ARM.
873 */
874static void ext_and_shift_reg(TCGv_i64 tcg_out, TCGv_i64 tcg_in,
875 int option, unsigned int shift)
876{
877 int extsize = extract32(option, 0, 2);
878 bool is_signed = extract32(option, 2, 1);
879
880 if (is_signed) {
881 switch (extsize) {
882 case 0:
883 tcg_gen_ext8s_i64(tcg_out, tcg_in);
884 break;
885 case 1:
886 tcg_gen_ext16s_i64(tcg_out, tcg_in);
887 break;
888 case 2:
889 tcg_gen_ext32s_i64(tcg_out, tcg_in);
890 break;
891 case 3:
892 tcg_gen_mov_i64(tcg_out, tcg_in);
893 break;
894 }
895 } else {
896 switch (extsize) {
897 case 0:
898 tcg_gen_ext8u_i64(tcg_out, tcg_in);
899 break;
900 case 1:
901 tcg_gen_ext16u_i64(tcg_out, tcg_in);
902 break;
903 case 2:
904 tcg_gen_ext32u_i64(tcg_out, tcg_in);
905 break;
906 case 3:
907 tcg_gen_mov_i64(tcg_out, tcg_in);
908 break;
909 }
910 }
911
912 if (shift) {
913 tcg_gen_shli_i64(tcg_out, tcg_out, shift);
914 }
915}
916
Peter Maydell4a08d472013-12-22 22:32:27 +0000917static inline void gen_check_sp_alignment(DisasContext *s)
918{
919 /* The AArch64 architecture mandates that (if enabled via PSTATE
920 * or SCTLR bits) there is a check that SP is 16-aligned on every
921 * SP-relative load or store (with an exception generated if it is not).
922 * In line with general QEMU practice regarding misaligned accesses,
923 * we omit these checks for the sake of guest program performance.
924 * This function is provided as a hook so we can more easily add these
925 * checks in future (possibly as a "favour catching guest program bugs
926 * over speed" user selectable option).
927 */
928}
929
930/*
Alex Bennée384b26f2014-01-31 14:47:30 +0000931 * This provides a simple table based table lookup decoder. It is
932 * intended to be used when the relevant bits for decode are too
933 * awkwardly placed and switch/if based logic would be confusing and
934 * deeply nested. Since it's a linear search through the table, tables
935 * should be kept small.
936 *
937 * It returns the first handler where insn & mask == pattern, or
938 * NULL if there is no match.
939 * The table is terminated by an empty mask (i.e. 0)
940 */
941static inline AArch64DecodeFn *lookup_disas_fn(const AArch64DecodeTable *table,
942 uint32_t insn)
943{
944 const AArch64DecodeTable *tptr = table;
945
946 while (tptr->mask) {
947 if ((insn & tptr->mask) == tptr->pattern) {
948 return tptr->disas_fn;
949 }
950 tptr++;
951 }
952 return NULL;
953}
954
955/*
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000956 * the instruction disassembly implemented here matches
957 * the instruction encoding classifications in chapter 3 (C3)
958 * of the ARM Architecture Reference Manual (DDI0487A_a)
959 */
960
Alexander Graf11e169d2013-12-17 19:42:32 +0000961/* C3.2.7 Unconditional branch (immediate)
962 * 31 30 26 25 0
963 * +----+-----------+-------------------------------------+
964 * | op | 0 0 1 0 1 | imm26 |
965 * +----+-----------+-------------------------------------+
966 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000967static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
968{
Alexander Graf11e169d2013-12-17 19:42:32 +0000969 uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
970
971 if (insn & (1 << 31)) {
972 /* C5.6.26 BL Branch with link */
973 tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
974 }
975
976 /* C5.6.20 B Branch / C5.6.26 BL Branch with link */
977 gen_goto_tb(s, 0, addr);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000978}
979
Alexander Graf60e53382013-12-17 19:42:33 +0000980/* C3.2.1 Compare & branch (immediate)
981 * 31 30 25 24 23 5 4 0
982 * +----+-------------+----+---------------------+--------+
983 * | sf | 0 1 1 0 1 0 | op | imm19 | Rt |
984 * +----+-------------+----+---------------------+--------+
985 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000986static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
987{
Alexander Graf60e53382013-12-17 19:42:33 +0000988 unsigned int sf, op, rt;
989 uint64_t addr;
990 int label_match;
991 TCGv_i64 tcg_cmp;
992
993 sf = extract32(insn, 31, 1);
994 op = extract32(insn, 24, 1); /* 0: CBZ; 1: CBNZ */
995 rt = extract32(insn, 0, 5);
996 addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
997
998 tcg_cmp = read_cpu_reg(s, rt, sf);
999 label_match = gen_new_label();
1000
1001 tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
1002 tcg_cmp, 0, label_match);
1003
1004 gen_goto_tb(s, 0, s->pc);
1005 gen_set_label(label_match);
1006 gen_goto_tb(s, 1, addr);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001007}
1008
Alexander Grafdb0f7952013-12-17 19:42:33 +00001009/* C3.2.5 Test & branch (immediate)
1010 * 31 30 25 24 23 19 18 5 4 0
1011 * +----+-------------+----+-------+-------------+------+
1012 * | b5 | 0 1 1 0 1 1 | op | b40 | imm14 | Rt |
1013 * +----+-------------+----+-------+-------------+------+
1014 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001015static void disas_test_b_imm(DisasContext *s, uint32_t insn)
1016{
Alexander Grafdb0f7952013-12-17 19:42:33 +00001017 unsigned int bit_pos, op, rt;
1018 uint64_t addr;
1019 int label_match;
1020 TCGv_i64 tcg_cmp;
1021
1022 bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
1023 op = extract32(insn, 24, 1); /* 0: TBZ; 1: TBNZ */
1024 addr = s->pc + sextract32(insn, 5, 14) * 4 - 4;
1025 rt = extract32(insn, 0, 5);
1026
1027 tcg_cmp = tcg_temp_new_i64();
1028 tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, rt), (1ULL << bit_pos));
1029 label_match = gen_new_label();
1030 tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
1031 tcg_cmp, 0, label_match);
1032 tcg_temp_free_i64(tcg_cmp);
1033 gen_goto_tb(s, 0, s->pc);
1034 gen_set_label(label_match);
1035 gen_goto_tb(s, 1, addr);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001036}
1037
Alexander Graf39fb7302013-12-17 19:42:33 +00001038/* C3.2.2 / C5.6.19 Conditional branch (immediate)
1039 * 31 25 24 23 5 4 3 0
1040 * +---------------+----+---------------------+----+------+
1041 * | 0 1 0 1 0 1 0 | o1 | imm19 | o0 | cond |
1042 * +---------------+----+---------------------+----+------+
1043 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001044static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
1045{
Alexander Graf39fb7302013-12-17 19:42:33 +00001046 unsigned int cond;
1047 uint64_t addr;
1048
1049 if ((insn & (1 << 4)) || (insn & (1 << 24))) {
1050 unallocated_encoding(s);
1051 return;
1052 }
1053 addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
1054 cond = extract32(insn, 0, 4);
1055
1056 if (cond < 0x0e) {
1057 /* genuinely conditional branches */
1058 int label_match = gen_new_label();
1059 arm_gen_test_cc(cond, label_match);
1060 gen_goto_tb(s, 0, s->pc);
1061 gen_set_label(label_match);
1062 gen_goto_tb(s, 1, addr);
1063 } else {
1064 /* 0xe and 0xf are both "always" conditions */
1065 gen_goto_tb(s, 0, addr);
1066 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001067}
1068
Claudio Fontana87462e02013-12-17 19:42:32 +00001069/* C5.6.68 HINT */
1070static void handle_hint(DisasContext *s, uint32_t insn,
1071 unsigned int op1, unsigned int op2, unsigned int crm)
1072{
1073 unsigned int selector = crm << 3 | op2;
1074
1075 if (op1 != 3) {
1076 unallocated_encoding(s);
1077 return;
1078 }
1079
1080 switch (selector) {
1081 case 0: /* NOP */
1082 return;
Peter Maydell1ed69e82014-02-26 17:20:06 +00001083 case 3: /* WFI */
1084 s->is_jmp = DISAS_WFI;
1085 return;
Claudio Fontana87462e02013-12-17 19:42:32 +00001086 case 1: /* YIELD */
1087 case 2: /* WFE */
Claudio Fontana87462e02013-12-17 19:42:32 +00001088 case 4: /* SEV */
1089 case 5: /* SEVL */
1090 /* we treat all as NOP at least for now */
1091 return;
1092 default:
1093 /* default specified as NOP equivalent */
1094 return;
1095 }
1096}
1097
Michael Matzfa2ef212014-01-04 22:15:47 +00001098static void gen_clrex(DisasContext *s, uint32_t insn)
1099{
1100 tcg_gen_movi_i64(cpu_exclusive_addr, -1);
1101}
1102
Claudio Fontana87462e02013-12-17 19:42:32 +00001103/* CLREX, DSB, DMB, ISB */
1104static void handle_sync(DisasContext *s, uint32_t insn,
1105 unsigned int op1, unsigned int op2, unsigned int crm)
1106{
1107 if (op1 != 3) {
1108 unallocated_encoding(s);
1109 return;
1110 }
1111
1112 switch (op2) {
1113 case 2: /* CLREX */
Michael Matzfa2ef212014-01-04 22:15:47 +00001114 gen_clrex(s, insn);
Claudio Fontana87462e02013-12-17 19:42:32 +00001115 return;
1116 case 4: /* DSB */
1117 case 5: /* DMB */
1118 case 6: /* ISB */
1119 /* We don't emulate caches so barriers are no-ops */
1120 return;
1121 default:
1122 unallocated_encoding(s);
1123 return;
1124 }
1125}
1126
1127/* C5.6.130 MSR (immediate) - move immediate to processor state field */
1128static void handle_msr_i(DisasContext *s, uint32_t insn,
1129 unsigned int op1, unsigned int op2, unsigned int crm)
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001130{
Peter Maydell9cfa0b42014-02-26 17:20:06 +00001131 int op = op1 << 3 | op2;
1132 switch (op) {
1133 case 0x05: /* SPSel */
1134 if (s->current_pl == 0) {
1135 unallocated_encoding(s);
1136 return;
1137 }
1138 /* fall through */
1139 case 0x1e: /* DAIFSet */
1140 case 0x1f: /* DAIFClear */
1141 {
1142 TCGv_i32 tcg_imm = tcg_const_i32(crm);
1143 TCGv_i32 tcg_op = tcg_const_i32(op);
1144 gen_a64_set_pc_im(s->pc - 4);
1145 gen_helper_msr_i_pstate(cpu_env, tcg_op, tcg_imm);
1146 tcg_temp_free_i32(tcg_imm);
1147 tcg_temp_free_i32(tcg_op);
1148 s->is_jmp = DISAS_UPDATE;
1149 break;
1150 }
1151 default:
1152 unallocated_encoding(s);
1153 return;
1154 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001155}
1156
Peter Maydellb0d2b7d2014-01-04 22:15:45 +00001157static void gen_get_nzcv(TCGv_i64 tcg_rt)
1158{
1159 TCGv_i32 tmp = tcg_temp_new_i32();
1160 TCGv_i32 nzcv = tcg_temp_new_i32();
1161
1162 /* build bit 31, N */
1163 tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
1164 /* build bit 30, Z */
1165 tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
1166 tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
1167 /* build bit 29, C */
1168 tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
1169 /* build bit 28, V */
1170 tcg_gen_shri_i32(tmp, cpu_VF, 31);
1171 tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
1172 /* generate result */
1173 tcg_gen_extu_i32_i64(tcg_rt, nzcv);
1174
1175 tcg_temp_free_i32(nzcv);
1176 tcg_temp_free_i32(tmp);
1177}
1178
1179static void gen_set_nzcv(TCGv_i64 tcg_rt)
1180
1181{
1182 TCGv_i32 nzcv = tcg_temp_new_i32();
1183
1184 /* take NZCV from R[t] */
1185 tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
1186
1187 /* bit 31, N */
1188 tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
1189 /* bit 30, Z */
1190 tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
1191 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
1192 /* bit 29, C */
1193 tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
1194 tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
1195 /* bit 28, V */
1196 tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
1197 tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
1198 tcg_temp_free_i32(nzcv);
1199}
1200
Peter Maydellfea50522014-01-04 22:15:45 +00001201/* C5.6.129 MRS - move from system register
1202 * C5.6.131 MSR (register) - move to system register
1203 * C5.6.204 SYS
1204 * C5.6.205 SYSL
1205 * These are all essentially the same insn in 'read' and 'write'
1206 * versions, with varying op0 fields.
1207 */
1208static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
1209 unsigned int op0, unsigned int op1, unsigned int op2,
Claudio Fontana87462e02013-12-17 19:42:32 +00001210 unsigned int crn, unsigned int crm, unsigned int rt)
1211{
Peter Maydellfea50522014-01-04 22:15:45 +00001212 const ARMCPRegInfo *ri;
1213 TCGv_i64 tcg_rt;
Claudio Fontana87462e02013-12-17 19:42:32 +00001214
Peter Maydellfea50522014-01-04 22:15:45 +00001215 ri = get_arm_cp_reginfo(s->cp_regs,
1216 ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
1217 crn, crm, op0, op1, op2));
Claudio Fontana87462e02013-12-17 19:42:32 +00001218
Peter Maydellfea50522014-01-04 22:15:45 +00001219 if (!ri) {
Peter Maydell626187d2014-02-20 10:35:52 +00001220 /* Unknown register; this might be a guest error or a QEMU
1221 * unimplemented feature.
1222 */
1223 qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch64 "
1224 "system register op0:%d op1:%d crn:%d crm:%d op2:%d\n",
1225 isread ? "read" : "write", op0, op1, crn, crm, op2);
Peter Maydellfea50522014-01-04 22:15:45 +00001226 unallocated_encoding(s);
1227 return;
1228 }
1229
1230 /* Check access permissions */
1231 if (!cp_access_ok(s->current_pl, ri, isread)) {
1232 unallocated_encoding(s);
1233 return;
1234 }
1235
Peter Maydellf59df3f2014-02-20 10:35:52 +00001236 if (ri->accessfn) {
1237 /* Emit code to perform further access permissions checks at
1238 * runtime; this may result in an exception.
1239 */
1240 TCGv_ptr tmpptr;
1241 gen_a64_set_pc_im(s->pc - 4);
1242 tmpptr = tcg_const_ptr(ri);
1243 gen_helper_access_check_cp_reg(cpu_env, tmpptr);
1244 tcg_temp_free_ptr(tmpptr);
1245 }
1246
Peter Maydellfea50522014-01-04 22:15:45 +00001247 /* Handle special cases first */
1248 switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
1249 case ARM_CP_NOP:
1250 return;
Peter Maydellb0d2b7d2014-01-04 22:15:45 +00001251 case ARM_CP_NZCV:
1252 tcg_rt = cpu_reg(s, rt);
1253 if (isread) {
1254 gen_get_nzcv(tcg_rt);
1255 } else {
1256 gen_set_nzcv(tcg_rt);
1257 }
1258 return;
Peter Maydell0eef9d92014-02-26 17:20:02 +00001259 case ARM_CP_CURRENTEL:
1260 /* Reads as current EL value from pstate, which is
1261 * guaranteed to be constant by the tb flags.
1262 */
1263 tcg_rt = cpu_reg(s, rt);
1264 tcg_gen_movi_i64(tcg_rt, s->current_pl << 2);
1265 return;
Peter Maydellfea50522014-01-04 22:15:45 +00001266 default:
1267 break;
1268 }
1269
1270 if (use_icount && (ri->type & ARM_CP_IO)) {
1271 gen_io_start();
1272 }
1273
1274 tcg_rt = cpu_reg(s, rt);
1275
1276 if (isread) {
1277 if (ri->type & ARM_CP_CONST) {
1278 tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
1279 } else if (ri->readfn) {
1280 TCGv_ptr tmpptr;
Peter Maydellfea50522014-01-04 22:15:45 +00001281 tmpptr = tcg_const_ptr(ri);
1282 gen_helper_get_cp_reg64(tcg_rt, cpu_env, tmpptr);
1283 tcg_temp_free_ptr(tmpptr);
1284 } else {
1285 tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset);
1286 }
1287 } else {
1288 if (ri->type & ARM_CP_CONST) {
1289 /* If not forbidden by access permissions, treat as WI */
1290 return;
1291 } else if (ri->writefn) {
1292 TCGv_ptr tmpptr;
Peter Maydellfea50522014-01-04 22:15:45 +00001293 tmpptr = tcg_const_ptr(ri);
1294 gen_helper_set_cp_reg64(cpu_env, tmpptr, tcg_rt);
1295 tcg_temp_free_ptr(tmpptr);
1296 } else {
1297 tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset);
1298 }
1299 }
1300
1301 if (use_icount && (ri->type & ARM_CP_IO)) {
1302 /* I/O operations must end the TB here (whether read or write) */
1303 gen_io_end();
1304 s->is_jmp = DISAS_UPDATE;
1305 } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
1306 /* We default to ending the TB on a coprocessor register write,
1307 * but allow this to be suppressed by the register definition
1308 * (usually only necessary to work around guest bugs).
1309 */
1310 s->is_jmp = DISAS_UPDATE;
1311 }
Claudio Fontana87462e02013-12-17 19:42:32 +00001312}
1313
1314/* C3.2.4 System
1315 * 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
1316 * +---------------------+---+-----+-----+-------+-------+-----+------+
1317 * | 1 1 0 1 0 1 0 1 0 0 | L | op0 | op1 | CRn | CRm | op2 | Rt |
1318 * +---------------------+---+-----+-----+-------+-------+-----+------+
1319 */
1320static void disas_system(DisasContext *s, uint32_t insn)
1321{
1322 unsigned int l, op0, op1, crn, crm, op2, rt;
1323 l = extract32(insn, 21, 1);
1324 op0 = extract32(insn, 19, 2);
1325 op1 = extract32(insn, 16, 3);
1326 crn = extract32(insn, 12, 4);
1327 crm = extract32(insn, 8, 4);
1328 op2 = extract32(insn, 5, 3);
1329 rt = extract32(insn, 0, 5);
1330
1331 if (op0 == 0) {
1332 if (l || rt != 31) {
1333 unallocated_encoding(s);
1334 return;
1335 }
1336 switch (crn) {
1337 case 2: /* C5.6.68 HINT */
1338 handle_hint(s, insn, op1, op2, crm);
1339 break;
1340 case 3: /* CLREX, DSB, DMB, ISB */
1341 handle_sync(s, insn, op1, op2, crm);
1342 break;
1343 case 4: /* C5.6.130 MSR (immediate) */
1344 handle_msr_i(s, insn, op1, op2, crm);
1345 break;
1346 default:
1347 unallocated_encoding(s);
1348 break;
1349 }
1350 return;
1351 }
Peter Maydellfea50522014-01-04 22:15:45 +00001352 handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);
Claudio Fontana87462e02013-12-17 19:42:32 +00001353}
1354
Alexander Graf9618e802013-12-23 23:27:30 +00001355/* C3.2.3 Exception generation
1356 *
1357 * 31 24 23 21 20 5 4 2 1 0
1358 * +-----------------+-----+------------------------+-----+----+
1359 * | 1 1 0 1 0 1 0 0 | opc | imm16 | op2 | LL |
1360 * +-----------------------+------------------------+----------+
1361 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001362static void disas_exc(DisasContext *s, uint32_t insn)
1363{
Alexander Graf9618e802013-12-23 23:27:30 +00001364 int opc = extract32(insn, 21, 3);
1365 int op2_ll = extract32(insn, 0, 5);
1366
1367 switch (opc) {
1368 case 0:
1369 /* SVC, HVC, SMC; since we don't support the Virtualization
1370 * or TrustZone extensions these all UNDEF except SVC.
1371 */
1372 if (op2_ll != 1) {
1373 unallocated_encoding(s);
1374 break;
1375 }
1376 gen_exception_insn(s, 0, EXCP_SWI);
1377 break;
1378 case 1:
1379 if (op2_ll != 0) {
1380 unallocated_encoding(s);
1381 break;
1382 }
1383 /* BRK */
1384 gen_exception_insn(s, 0, EXCP_BKPT);
1385 break;
1386 case 2:
1387 if (op2_ll != 0) {
1388 unallocated_encoding(s);
1389 break;
1390 }
1391 /* HLT */
1392 unsupported_encoding(s, insn);
1393 break;
1394 case 5:
1395 if (op2_ll < 1 || op2_ll > 3) {
1396 unallocated_encoding(s);
1397 break;
1398 }
1399 /* DCPS1, DCPS2, DCPS3 */
1400 unsupported_encoding(s, insn);
1401 break;
1402 default:
1403 unallocated_encoding(s);
1404 break;
1405 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001406}
1407
Alexander Grafb001c8c2013-12-17 19:42:33 +00001408/* C3.2.7 Unconditional branch (register)
1409 * 31 25 24 21 20 16 15 10 9 5 4 0
1410 * +---------------+-------+-------+-------+------+-------+
1411 * | 1 1 0 1 0 1 1 | opc | op2 | op3 | Rn | op4 |
1412 * +---------------+-------+-------+-------+------+-------+
1413 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001414static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
1415{
Alexander Grafb001c8c2013-12-17 19:42:33 +00001416 unsigned int opc, op2, op3, rn, op4;
1417
1418 opc = extract32(insn, 21, 4);
1419 op2 = extract32(insn, 16, 5);
1420 op3 = extract32(insn, 10, 6);
1421 rn = extract32(insn, 5, 5);
1422 op4 = extract32(insn, 0, 5);
1423
1424 if (op4 != 0x0 || op3 != 0x0 || op2 != 0x1f) {
1425 unallocated_encoding(s);
1426 return;
1427 }
1428
1429 switch (opc) {
1430 case 0: /* BR */
1431 case 2: /* RET */
1432 break;
1433 case 1: /* BLR */
1434 tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
1435 break;
1436 case 4: /* ERET */
1437 case 5: /* DRPS */
1438 if (rn != 0x1f) {
1439 unallocated_encoding(s);
1440 } else {
1441 unsupported_encoding(s, insn);
1442 }
1443 return;
1444 default:
1445 unallocated_encoding(s);
1446 return;
1447 }
1448
1449 tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
1450 s->is_jmp = DISAS_JUMP;
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001451}
1452
1453/* C3.2 Branches, exception generating and system instructions */
1454static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
1455{
1456 switch (extract32(insn, 25, 7)) {
1457 case 0x0a: case 0x0b:
1458 case 0x4a: case 0x4b: /* Unconditional branch (immediate) */
1459 disas_uncond_b_imm(s, insn);
1460 break;
1461 case 0x1a: case 0x5a: /* Compare & branch (immediate) */
1462 disas_comp_b_imm(s, insn);
1463 break;
1464 case 0x1b: case 0x5b: /* Test & branch (immediate) */
1465 disas_test_b_imm(s, insn);
1466 break;
1467 case 0x2a: /* Conditional branch (immediate) */
1468 disas_cond_b_imm(s, insn);
1469 break;
1470 case 0x6a: /* Exception generation / System */
1471 if (insn & (1 << 24)) {
1472 disas_system(s, insn);
1473 } else {
1474 disas_exc(s, insn);
1475 }
1476 break;
1477 case 0x6b: /* Unconditional branch (register) */
1478 disas_uncond_b_reg(s, insn);
1479 break;
1480 default:
1481 unallocated_encoding(s);
1482 break;
1483 }
1484}
1485
Michael Matzfa2ef212014-01-04 22:15:47 +00001486/*
1487 * Load/Store exclusive instructions are implemented by remembering
1488 * the value/address loaded, and seeing if these are the same
1489 * when the store is performed. This is not actually the architecturally
1490 * mandated semantics, but it works for typical guest code sequences
1491 * and avoids having to monitor regular stores.
1492 *
1493 * In system emulation mode only one CPU will be running at once, so
1494 * this sequence is effectively atomic. In user emulation mode we
1495 * throw an exception and handle the atomic operation elsewhere.
1496 */
1497static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
1498 TCGv_i64 addr, int size, bool is_pair)
1499{
1500 TCGv_i64 tmp = tcg_temp_new_i64();
1501 TCGMemOp memop = MO_TE + size;
1502
1503 g_assert(size <= 3);
1504 tcg_gen_qemu_ld_i64(tmp, addr, get_mem_index(s), memop);
1505
1506 if (is_pair) {
1507 TCGv_i64 addr2 = tcg_temp_new_i64();
1508 TCGv_i64 hitmp = tcg_temp_new_i64();
1509
1510 g_assert(size >= 2);
1511 tcg_gen_addi_i64(addr2, addr, 1 << size);
1512 tcg_gen_qemu_ld_i64(hitmp, addr2, get_mem_index(s), memop);
1513 tcg_temp_free_i64(addr2);
1514 tcg_gen_mov_i64(cpu_exclusive_high, hitmp);
1515 tcg_gen_mov_i64(cpu_reg(s, rt2), hitmp);
1516 tcg_temp_free_i64(hitmp);
1517 }
1518
1519 tcg_gen_mov_i64(cpu_exclusive_val, tmp);
1520 tcg_gen_mov_i64(cpu_reg(s, rt), tmp);
1521
1522 tcg_temp_free_i64(tmp);
1523 tcg_gen_mov_i64(cpu_exclusive_addr, addr);
1524}
1525
1526#ifdef CONFIG_USER_ONLY
1527static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
1528 TCGv_i64 addr, int size, int is_pair)
1529{
1530 tcg_gen_mov_i64(cpu_exclusive_test, addr);
1531 tcg_gen_movi_i32(cpu_exclusive_info,
1532 size | is_pair << 2 | (rd << 4) | (rt << 9) | (rt2 << 14));
1533 gen_exception_insn(s, 4, EXCP_STREX);
1534}
1535#else
1536static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
Peter Maydelld324b362014-02-20 10:35:55 +00001537 TCGv_i64 inaddr, int size, int is_pair)
Michael Matzfa2ef212014-01-04 22:15:47 +00001538{
Peter Maydelld324b362014-02-20 10:35:55 +00001539 /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]
1540 * && (!is_pair || env->exclusive_high == [addr + datasize])) {
1541 * [addr] = {Rt};
1542 * if (is_pair) {
1543 * [addr + datasize] = {Rt2};
1544 * }
1545 * {Rd} = 0;
1546 * } else {
1547 * {Rd} = 1;
1548 * }
1549 * env->exclusive_addr = -1;
1550 */
1551 int fail_label = gen_new_label();
1552 int done_label = gen_new_label();
1553 TCGv_i64 addr = tcg_temp_local_new_i64();
1554 TCGv_i64 tmp;
1555
1556 /* Copy input into a local temp so it is not trashed when the
1557 * basic block ends at the branch insn.
1558 */
1559 tcg_gen_mov_i64(addr, inaddr);
1560 tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
1561
1562 tmp = tcg_temp_new_i64();
1563 tcg_gen_qemu_ld_i64(tmp, addr, get_mem_index(s), MO_TE + size);
1564 tcg_gen_brcond_i64(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
1565 tcg_temp_free_i64(tmp);
1566
1567 if (is_pair) {
1568 TCGv_i64 addrhi = tcg_temp_new_i64();
1569 TCGv_i64 tmphi = tcg_temp_new_i64();
1570
1571 tcg_gen_addi_i64(addrhi, addr, 1 << size);
1572 tcg_gen_qemu_ld_i64(tmphi, addrhi, get_mem_index(s), MO_TE + size);
1573 tcg_gen_brcond_i64(TCG_COND_NE, tmphi, cpu_exclusive_high, fail_label);
1574
1575 tcg_temp_free_i64(tmphi);
1576 tcg_temp_free_i64(addrhi);
1577 }
1578
1579 /* We seem to still have the exclusive monitor, so do the store */
1580 tcg_gen_qemu_st_i64(cpu_reg(s, rt), addr, get_mem_index(s), MO_TE + size);
1581 if (is_pair) {
1582 TCGv_i64 addrhi = tcg_temp_new_i64();
1583
1584 tcg_gen_addi_i64(addrhi, addr, 1 << size);
1585 tcg_gen_qemu_st_i64(cpu_reg(s, rt2), addrhi,
1586 get_mem_index(s), MO_TE + size);
1587 tcg_temp_free_i64(addrhi);
1588 }
1589
1590 tcg_temp_free_i64(addr);
1591
1592 tcg_gen_movi_i64(cpu_reg(s, rd), 0);
1593 tcg_gen_br(done_label);
1594 gen_set_label(fail_label);
1595 tcg_gen_movi_i64(cpu_reg(s, rd), 1);
1596 gen_set_label(done_label);
1597 tcg_gen_movi_i64(cpu_exclusive_addr, -1);
1598
Michael Matzfa2ef212014-01-04 22:15:47 +00001599}
1600#endif
1601
1602/* C3.3.6 Load/store exclusive
1603 *
1604 * 31 30 29 24 23 22 21 20 16 15 14 10 9 5 4 0
1605 * +-----+-------------+----+---+----+------+----+-------+------+------+
1606 * | sz | 0 0 1 0 0 0 | o2 | L | o1 | Rs | o0 | Rt2 | Rn | Rt |
1607 * +-----+-------------+----+---+----+------+----+-------+------+------+
1608 *
1609 * sz: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64 bit
1610 * L: 0 -> store, 1 -> load
1611 * o2: 0 -> exclusive, 1 -> not
1612 * o1: 0 -> single register, 1 -> register pair
1613 * o0: 1 -> load-acquire/store-release, 0 -> not
1614 *
1615 * o0 == 0 AND o2 == 1 is un-allocated
1616 * o1 == 1 is un-allocated except for 32 and 64 bit sizes
1617 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001618static void disas_ldst_excl(DisasContext *s, uint32_t insn)
1619{
Michael Matzfa2ef212014-01-04 22:15:47 +00001620 int rt = extract32(insn, 0, 5);
1621 int rn = extract32(insn, 5, 5);
1622 int rt2 = extract32(insn, 10, 5);
1623 int is_lasr = extract32(insn, 15, 1);
1624 int rs = extract32(insn, 16, 5);
1625 int is_pair = extract32(insn, 21, 1);
1626 int is_store = !extract32(insn, 22, 1);
1627 int is_excl = !extract32(insn, 23, 1);
1628 int size = extract32(insn, 30, 2);
1629 TCGv_i64 tcg_addr;
1630
1631 if ((!is_excl && !is_lasr) ||
1632 (is_pair && size < 2)) {
1633 unallocated_encoding(s);
1634 return;
1635 }
1636
1637 if (rn == 31) {
1638 gen_check_sp_alignment(s);
1639 }
1640 tcg_addr = read_cpu_reg_sp(s, rn, 1);
1641
1642 /* Note that since TCG is single threaded load-acquire/store-release
1643 * semantics require no extra if (is_lasr) { ... } handling.
1644 */
1645
1646 if (is_excl) {
1647 if (!is_store) {
1648 gen_load_exclusive(s, rt, rt2, tcg_addr, size, is_pair);
1649 } else {
1650 gen_store_exclusive(s, rs, rt, rt2, tcg_addr, size, is_pair);
1651 }
1652 } else {
1653 TCGv_i64 tcg_rt = cpu_reg(s, rt);
1654 if (is_store) {
1655 do_gpr_st(s, tcg_rt, tcg_addr, size);
1656 } else {
1657 do_gpr_ld(s, tcg_rt, tcg_addr, size, false, false);
1658 }
1659 if (is_pair) {
1660 TCGv_i64 tcg_rt2 = cpu_reg(s, rt);
1661 tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
1662 if (is_store) {
1663 do_gpr_st(s, tcg_rt2, tcg_addr, size);
1664 } else {
1665 do_gpr_ld(s, tcg_rt2, tcg_addr, size, false, false);
1666 }
1667 }
1668 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001669}
1670
Alexander Graf32b64e82014-01-04 22:15:46 +00001671/*
1672 * C3.3.5 Load register (literal)
1673 *
1674 * 31 30 29 27 26 25 24 23 5 4 0
1675 * +-----+-------+---+-----+-------------------+-------+
1676 * | opc | 0 1 1 | V | 0 0 | imm19 | Rt |
1677 * +-----+-------+---+-----+-------------------+-------+
1678 *
1679 * V: 1 -> vector (simd/fp)
1680 * opc (non-vector): 00 -> 32 bit, 01 -> 64 bit,
1681 * 10-> 32 bit signed, 11 -> prefetch
1682 * opc (vector): 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit (11 unallocated)
1683 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001684static void disas_ld_lit(DisasContext *s, uint32_t insn)
1685{
Alexander Graf32b64e82014-01-04 22:15:46 +00001686 int rt = extract32(insn, 0, 5);
1687 int64_t imm = sextract32(insn, 5, 19) << 2;
1688 bool is_vector = extract32(insn, 26, 1);
1689 int opc = extract32(insn, 30, 2);
1690 bool is_signed = false;
1691 int size = 2;
1692 TCGv_i64 tcg_rt, tcg_addr;
1693
1694 if (is_vector) {
1695 if (opc == 3) {
1696 unallocated_encoding(s);
1697 return;
1698 }
1699 size = 2 + opc;
1700 } else {
1701 if (opc == 3) {
1702 /* PRFM (literal) : prefetch */
1703 return;
1704 }
1705 size = 2 + extract32(opc, 0, 1);
1706 is_signed = extract32(opc, 1, 1);
1707 }
1708
1709 tcg_rt = cpu_reg(s, rt);
1710
1711 tcg_addr = tcg_const_i64((s->pc - 4) + imm);
1712 if (is_vector) {
1713 do_fp_ld(s, rt, tcg_addr, size);
1714 } else {
1715 do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false);
1716 }
1717 tcg_temp_free_i64(tcg_addr);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001718}
1719
Peter Maydell4a08d472013-12-22 22:32:27 +00001720/*
1721 * C5.6.80 LDNP (Load Pair - non-temporal hint)
1722 * C5.6.81 LDP (Load Pair - non vector)
1723 * C5.6.82 LDPSW (Load Pair Signed Word - non vector)
1724 * C5.6.176 STNP (Store Pair - non-temporal hint)
1725 * C5.6.177 STP (Store Pair - non vector)
1726 * C6.3.165 LDNP (Load Pair of SIMD&FP - non-temporal hint)
1727 * C6.3.165 LDP (Load Pair of SIMD&FP)
1728 * C6.3.284 STNP (Store Pair of SIMD&FP - non-temporal hint)
1729 * C6.3.284 STP (Store Pair of SIMD&FP)
1730 *
1731 * 31 30 29 27 26 25 24 23 22 21 15 14 10 9 5 4 0
1732 * +-----+-------+---+---+-------+---+-----------------------------+
1733 * | opc | 1 0 1 | V | 0 | index | L | imm7 | Rt2 | Rn | Rt |
1734 * +-----+-------+---+---+-------+---+-------+-------+------+------+
1735 *
1736 * opc: LDP/STP/LDNP/STNP 00 -> 32 bit, 10 -> 64 bit
1737 * LDPSW 01
1738 * LDP/STP/LDNP/STNP (SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit
1739 * V: 0 -> GPR, 1 -> Vector
1740 * idx: 00 -> signed offset with non-temporal hint, 01 -> post-index,
1741 * 10 -> signed offset, 11 -> pre-index
1742 * L: 0 -> Store 1 -> Load
1743 *
1744 * Rt, Rt2 = GPR or SIMD registers to be stored
1745 * Rn = general purpose register containing address
1746 * imm7 = signed offset (multiple of 4 or 8 depending on size)
1747 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001748static void disas_ldst_pair(DisasContext *s, uint32_t insn)
1749{
Peter Maydell4a08d472013-12-22 22:32:27 +00001750 int rt = extract32(insn, 0, 5);
1751 int rn = extract32(insn, 5, 5);
1752 int rt2 = extract32(insn, 10, 5);
1753 int64_t offset = sextract32(insn, 15, 7);
1754 int index = extract32(insn, 23, 2);
1755 bool is_vector = extract32(insn, 26, 1);
1756 bool is_load = extract32(insn, 22, 1);
1757 int opc = extract32(insn, 30, 2);
1758
1759 bool is_signed = false;
1760 bool postindex = false;
1761 bool wback = false;
1762
1763 TCGv_i64 tcg_addr; /* calculated address */
1764 int size;
1765
1766 if (opc == 3) {
1767 unallocated_encoding(s);
1768 return;
1769 }
1770
1771 if (is_vector) {
1772 size = 2 + opc;
1773 } else {
1774 size = 2 + extract32(opc, 1, 1);
1775 is_signed = extract32(opc, 0, 1);
1776 if (!is_load && is_signed) {
1777 unallocated_encoding(s);
1778 return;
1779 }
1780 }
1781
1782 switch (index) {
1783 case 1: /* post-index */
1784 postindex = true;
1785 wback = true;
1786 break;
1787 case 0:
1788 /* signed offset with "non-temporal" hint. Since we don't emulate
1789 * caches we don't care about hints to the cache system about
1790 * data access patterns, and handle this identically to plain
1791 * signed offset.
1792 */
1793 if (is_signed) {
1794 /* There is no non-temporal-hint version of LDPSW */
1795 unallocated_encoding(s);
1796 return;
1797 }
1798 postindex = false;
1799 break;
1800 case 2: /* signed offset, rn not updated */
1801 postindex = false;
1802 break;
1803 case 3: /* pre-index */
1804 postindex = false;
1805 wback = true;
1806 break;
1807 }
1808
1809 offset <<= size;
1810
1811 if (rn == 31) {
1812 gen_check_sp_alignment(s);
1813 }
1814
1815 tcg_addr = read_cpu_reg_sp(s, rn, 1);
1816
1817 if (!postindex) {
1818 tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
1819 }
1820
1821 if (is_vector) {
1822 if (is_load) {
1823 do_fp_ld(s, rt, tcg_addr, size);
1824 } else {
1825 do_fp_st(s, rt, tcg_addr, size);
1826 }
1827 } else {
1828 TCGv_i64 tcg_rt = cpu_reg(s, rt);
1829 if (is_load) {
1830 do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false);
1831 } else {
1832 do_gpr_st(s, tcg_rt, tcg_addr, size);
1833 }
1834 }
1835 tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
1836 if (is_vector) {
1837 if (is_load) {
1838 do_fp_ld(s, rt2, tcg_addr, size);
1839 } else {
1840 do_fp_st(s, rt2, tcg_addr, size);
1841 }
1842 } else {
1843 TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
1844 if (is_load) {
1845 do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false);
1846 } else {
1847 do_gpr_st(s, tcg_rt2, tcg_addr, size);
1848 }
1849 }
1850
1851 if (wback) {
1852 if (postindex) {
1853 tcg_gen_addi_i64(tcg_addr, tcg_addr, offset - (1 << size));
1854 } else {
1855 tcg_gen_subi_i64(tcg_addr, tcg_addr, 1 << size);
1856 }
1857 tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
1858 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00001859}
1860
Alex Bennéed5612f12013-12-23 23:27:28 +00001861/*
Alex Bennéea5e94a92013-12-23 23:27:29 +00001862 * C3.3.8 Load/store (immediate post-indexed)
1863 * C3.3.9 Load/store (immediate pre-indexed)
1864 * C3.3.12 Load/store (unscaled immediate)
1865 *
1866 * 31 30 29 27 26 25 24 23 22 21 20 12 11 10 9 5 4 0
1867 * +----+-------+---+-----+-----+---+--------+-----+------+------+
1868 * |size| 1 1 1 | V | 0 0 | opc | 0 | imm9 | idx | Rn | Rt |
1869 * +----+-------+---+-----+-----+---+--------+-----+------+------+
1870 *
1871 * idx = 01 -> post-indexed, 11 pre-indexed, 00 unscaled imm. (no writeback)
Peter Maydell60510ae2014-02-20 10:35:56 +00001872 10 -> unprivileged
Alex Bennéea5e94a92013-12-23 23:27:29 +00001873 * V = 0 -> non-vector
1874 * size: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64bit
1875 * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
1876 */
1877static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn)
1878{
1879 int rt = extract32(insn, 0, 5);
1880 int rn = extract32(insn, 5, 5);
1881 int imm9 = sextract32(insn, 12, 9);
1882 int opc = extract32(insn, 22, 2);
1883 int size = extract32(insn, 30, 2);
1884 int idx = extract32(insn, 10, 2);
1885 bool is_signed = false;
1886 bool is_store = false;
1887 bool is_extended = false;
Peter Maydell60510ae2014-02-20 10:35:56 +00001888 bool is_unpriv = (idx == 2);
Alex Bennéea5e94a92013-12-23 23:27:29 +00001889 bool is_vector = extract32(insn, 26, 1);
1890 bool post_index;
1891 bool writeback;
1892
1893 TCGv_i64 tcg_addr;
1894
1895 if (is_vector) {
1896 size |= (opc & 2) << 1;
Peter Maydell60510ae2014-02-20 10:35:56 +00001897 if (size > 4 || is_unpriv) {
Alex Bennéea5e94a92013-12-23 23:27:29 +00001898 unallocated_encoding(s);
1899 return;
1900 }
1901 is_store = ((opc & 1) == 0);
1902 } else {
1903 if (size == 3 && opc == 2) {
1904 /* PRFM - prefetch */
Peter Maydell60510ae2014-02-20 10:35:56 +00001905 if (is_unpriv) {
1906 unallocated_encoding(s);
1907 return;
1908 }
Alex Bennéea5e94a92013-12-23 23:27:29 +00001909 return;
1910 }
1911 if (opc == 3 && size > 1) {
1912 unallocated_encoding(s);
1913 return;
1914 }
1915 is_store = (opc == 0);
1916 is_signed = opc & (1<<1);
1917 is_extended = (size < 3) && (opc & 1);
1918 }
1919
1920 switch (idx) {
1921 case 0:
Peter Maydell60510ae2014-02-20 10:35:56 +00001922 case 2:
Alex Bennéea5e94a92013-12-23 23:27:29 +00001923 post_index = false;
1924 writeback = false;
1925 break;
1926 case 1:
1927 post_index = true;
1928 writeback = true;
1929 break;
1930 case 3:
1931 post_index = false;
1932 writeback = true;
1933 break;
Alex Bennéea5e94a92013-12-23 23:27:29 +00001934 }
1935
1936 if (rn == 31) {
1937 gen_check_sp_alignment(s);
1938 }
1939 tcg_addr = read_cpu_reg_sp(s, rn, 1);
1940
1941 if (!post_index) {
1942 tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
1943 }
1944
1945 if (is_vector) {
1946 if (is_store) {
1947 do_fp_st(s, rt, tcg_addr, size);
1948 } else {
1949 do_fp_ld(s, rt, tcg_addr, size);
1950 }
1951 } else {
1952 TCGv_i64 tcg_rt = cpu_reg(s, rt);
Peter Maydell60510ae2014-02-20 10:35:56 +00001953 int memidx = is_unpriv ? 1 : get_mem_index(s);
1954
Alex Bennéea5e94a92013-12-23 23:27:29 +00001955 if (is_store) {
Peter Maydell60510ae2014-02-20 10:35:56 +00001956 do_gpr_st_memidx(s, tcg_rt, tcg_addr, size, memidx);
Alex Bennéea5e94a92013-12-23 23:27:29 +00001957 } else {
Peter Maydell60510ae2014-02-20 10:35:56 +00001958 do_gpr_ld_memidx(s, tcg_rt, tcg_addr, size,
1959 is_signed, is_extended, memidx);
Alex Bennéea5e94a92013-12-23 23:27:29 +00001960 }
1961 }
1962
1963 if (writeback) {
1964 TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
1965 if (post_index) {
1966 tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
1967 }
1968 tcg_gen_mov_i64(tcg_rn, tcg_addr);
1969 }
1970}
1971
1972/*
Alex Bennée229b7a02013-12-23 23:27:29 +00001973 * C3.3.10 Load/store (register offset)
1974 *
1975 * 31 30 29 27 26 25 24 23 22 21 20 16 15 13 12 11 10 9 5 4 0
1976 * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
1977 * |size| 1 1 1 | V | 0 0 | opc | 1 | Rm | opt | S| 1 0 | Rn | Rt |
1978 * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
1979 *
1980 * For non-vector:
1981 * size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
1982 * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
1983 * For vector:
1984 * size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
1985 * opc<0>: 0 -> store, 1 -> load
1986 * V: 1 -> vector/simd
1987 * opt: extend encoding (see DecodeRegExtend)
1988 * S: if S=1 then scale (essentially index by sizeof(size))
1989 * Rt: register to transfer into/out of
1990 * Rn: address register or SP for base
1991 * Rm: offset register or ZR for offset
1992 */
1993static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn)
1994{
1995 int rt = extract32(insn, 0, 5);
1996 int rn = extract32(insn, 5, 5);
1997 int shift = extract32(insn, 12, 1);
1998 int rm = extract32(insn, 16, 5);
1999 int opc = extract32(insn, 22, 2);
2000 int opt = extract32(insn, 13, 3);
2001 int size = extract32(insn, 30, 2);
2002 bool is_signed = false;
2003 bool is_store = false;
2004 bool is_extended = false;
2005 bool is_vector = extract32(insn, 26, 1);
2006
2007 TCGv_i64 tcg_rm;
2008 TCGv_i64 tcg_addr;
2009
2010 if (extract32(opt, 1, 1) == 0) {
2011 unallocated_encoding(s);
2012 return;
2013 }
2014
2015 if (is_vector) {
2016 size |= (opc & 2) << 1;
2017 if (size > 4) {
2018 unallocated_encoding(s);
2019 return;
2020 }
2021 is_store = !extract32(opc, 0, 1);
2022 } else {
2023 if (size == 3 && opc == 2) {
2024 /* PRFM - prefetch */
2025 return;
2026 }
2027 if (opc == 3 && size > 1) {
2028 unallocated_encoding(s);
2029 return;
2030 }
2031 is_store = (opc == 0);
2032 is_signed = extract32(opc, 1, 1);
2033 is_extended = (size < 3) && extract32(opc, 0, 1);
2034 }
2035
2036 if (rn == 31) {
2037 gen_check_sp_alignment(s);
2038 }
2039 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2040
2041 tcg_rm = read_cpu_reg(s, rm, 1);
2042 ext_and_shift_reg(tcg_rm, tcg_rm, opt, shift ? size : 0);
2043
2044 tcg_gen_add_i64(tcg_addr, tcg_addr, tcg_rm);
2045
2046 if (is_vector) {
2047 if (is_store) {
2048 do_fp_st(s, rt, tcg_addr, size);
2049 } else {
2050 do_fp_ld(s, rt, tcg_addr, size);
2051 }
2052 } else {
2053 TCGv_i64 tcg_rt = cpu_reg(s, rt);
2054 if (is_store) {
2055 do_gpr_st(s, tcg_rt, tcg_addr, size);
2056 } else {
2057 do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
2058 }
2059 }
2060}
2061
2062/*
Alex Bennéed5612f12013-12-23 23:27:28 +00002063 * C3.3.13 Load/store (unsigned immediate)
2064 *
2065 * 31 30 29 27 26 25 24 23 22 21 10 9 5
2066 * +----+-------+---+-----+-----+------------+-------+------+
2067 * |size| 1 1 1 | V | 0 1 | opc | imm12 | Rn | Rt |
2068 * +----+-------+---+-----+-----+------------+-------+------+
2069 *
2070 * For non-vector:
2071 * size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
2072 * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
2073 * For vector:
2074 * size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
2075 * opc<0>: 0 -> store, 1 -> load
2076 * Rn: base address register (inc SP)
2077 * Rt: target register
2078 */
2079static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn)
2080{
2081 int rt = extract32(insn, 0, 5);
2082 int rn = extract32(insn, 5, 5);
2083 unsigned int imm12 = extract32(insn, 10, 12);
2084 bool is_vector = extract32(insn, 26, 1);
2085 int size = extract32(insn, 30, 2);
2086 int opc = extract32(insn, 22, 2);
2087 unsigned int offset;
2088
2089 TCGv_i64 tcg_addr;
2090
2091 bool is_store;
2092 bool is_signed = false;
2093 bool is_extended = false;
2094
2095 if (is_vector) {
2096 size |= (opc & 2) << 1;
2097 if (size > 4) {
2098 unallocated_encoding(s);
2099 return;
2100 }
2101 is_store = !extract32(opc, 0, 1);
2102 } else {
2103 if (size == 3 && opc == 2) {
2104 /* PRFM - prefetch */
2105 return;
2106 }
2107 if (opc == 3 && size > 1) {
2108 unallocated_encoding(s);
2109 return;
2110 }
2111 is_store = (opc == 0);
2112 is_signed = extract32(opc, 1, 1);
2113 is_extended = (size < 3) && extract32(opc, 0, 1);
2114 }
2115
2116 if (rn == 31) {
2117 gen_check_sp_alignment(s);
2118 }
2119 tcg_addr = read_cpu_reg_sp(s, rn, 1);
2120 offset = imm12 << size;
2121 tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
2122
2123 if (is_vector) {
2124 if (is_store) {
2125 do_fp_st(s, rt, tcg_addr, size);
2126 } else {
2127 do_fp_ld(s, rt, tcg_addr, size);
2128 }
2129 } else {
2130 TCGv_i64 tcg_rt = cpu_reg(s, rt);
2131 if (is_store) {
2132 do_gpr_st(s, tcg_rt, tcg_addr, size);
2133 } else {
2134 do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
2135 }
2136 }
2137}
2138
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002139/* Load/store register (all forms) */
2140static void disas_ldst_reg(DisasContext *s, uint32_t insn)
2141{
Alex Bennéed5612f12013-12-23 23:27:28 +00002142 switch (extract32(insn, 24, 2)) {
2143 case 0:
Alex Bennée229b7a02013-12-23 23:27:29 +00002144 if (extract32(insn, 21, 1) == 1 && extract32(insn, 10, 2) == 2) {
2145 disas_ldst_reg_roffset(s, insn);
2146 } else {
Peter Maydell60510ae2014-02-20 10:35:56 +00002147 /* Load/store register (unscaled immediate)
2148 * Load/store immediate pre/post-indexed
2149 * Load/store register unprivileged
2150 */
2151 disas_ldst_reg_imm9(s, insn);
Alex Bennée229b7a02013-12-23 23:27:29 +00002152 }
Alex Bennéed5612f12013-12-23 23:27:28 +00002153 break;
2154 case 1:
2155 disas_ldst_reg_unsigned_imm(s, insn);
2156 break;
2157 default:
2158 unallocated_encoding(s);
2159 break;
2160 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002161}
2162
Alex Bennée72430bf2014-01-31 14:47:30 +00002163/* C3.3.1 AdvSIMD load/store multiple structures
2164 *
2165 * 31 30 29 23 22 21 16 15 12 11 10 9 5 4 0
2166 * +---+---+---------------+---+-------------+--------+------+------+------+
2167 * | 0 | Q | 0 0 1 1 0 0 0 | L | 0 0 0 0 0 0 | opcode | size | Rn | Rt |
2168 * +---+---+---------------+---+-------------+--------+------+------+------+
2169 *
2170 * C3.3.2 AdvSIMD load/store multiple structures (post-indexed)
2171 *
2172 * 31 30 29 23 22 21 20 16 15 12 11 10 9 5 4 0
2173 * +---+---+---------------+---+---+---------+--------+------+------+------+
2174 * | 0 | Q | 0 0 1 1 0 0 1 | L | 0 | Rm | opcode | size | Rn | Rt |
2175 * +---+---+---------------+---+---+---------+--------+------+------+------+
2176 *
2177 * Rt: first (or only) SIMD&FP register to be transferred
2178 * Rn: base address or SP
2179 * Rm (post-index only): post-index register (when !31) or size dependent #imm
2180 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002181static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
2182{
Alex Bennée72430bf2014-01-31 14:47:30 +00002183 int rt = extract32(insn, 0, 5);
2184 int rn = extract32(insn, 5, 5);
2185 int size = extract32(insn, 10, 2);
2186 int opcode = extract32(insn, 12, 4);
2187 bool is_store = !extract32(insn, 22, 1);
2188 bool is_postidx = extract32(insn, 23, 1);
2189 bool is_q = extract32(insn, 30, 1);
2190 TCGv_i64 tcg_addr, tcg_rn;
2191
2192 int ebytes = 1 << size;
2193 int elements = (is_q ? 128 : 64) / (8 << size);
2194 int rpt; /* num iterations */
2195 int selem; /* structure elements */
2196 int r;
2197
2198 if (extract32(insn, 31, 1) || extract32(insn, 21, 1)) {
2199 unallocated_encoding(s);
2200 return;
2201 }
2202
2203 /* From the shared decode logic */
2204 switch (opcode) {
2205 case 0x0:
2206 rpt = 1;
2207 selem = 4;
2208 break;
2209 case 0x2:
2210 rpt = 4;
2211 selem = 1;
2212 break;
2213 case 0x4:
2214 rpt = 1;
2215 selem = 3;
2216 break;
2217 case 0x6:
2218 rpt = 3;
2219 selem = 1;
2220 break;
2221 case 0x7:
2222 rpt = 1;
2223 selem = 1;
2224 break;
2225 case 0x8:
2226 rpt = 1;
2227 selem = 2;
2228 break;
2229 case 0xa:
2230 rpt = 2;
2231 selem = 1;
2232 break;
2233 default:
2234 unallocated_encoding(s);
2235 return;
2236 }
2237
2238 if (size == 3 && !is_q && selem != 1) {
2239 /* reserved */
2240 unallocated_encoding(s);
2241 return;
2242 }
2243
2244 if (rn == 31) {
2245 gen_check_sp_alignment(s);
2246 }
2247
2248 tcg_rn = cpu_reg_sp(s, rn);
2249 tcg_addr = tcg_temp_new_i64();
2250 tcg_gen_mov_i64(tcg_addr, tcg_rn);
2251
2252 for (r = 0; r < rpt; r++) {
2253 int e;
2254 for (e = 0; e < elements; e++) {
2255 int tt = (rt + r) % 32;
2256 int xs;
2257 for (xs = 0; xs < selem; xs++) {
2258 if (is_store) {
2259 do_vec_st(s, tt, e, tcg_addr, size);
2260 } else {
2261 do_vec_ld(s, tt, e, tcg_addr, size);
2262
2263 /* For non-quad operations, setting a slice of the low
2264 * 64 bits of the register clears the high 64 bits (in
2265 * the ARM ARM pseudocode this is implicit in the fact
2266 * that 'rval' is a 64 bit wide variable). We optimize
2267 * by noticing that we only need to do this the first
2268 * time we touch a register.
2269 */
2270 if (!is_q && e == 0 && (r == 0 || xs == selem - 1)) {
2271 clear_vec_high(s, tt);
2272 }
2273 }
2274 tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes);
2275 tt = (tt + 1) % 32;
2276 }
2277 }
2278 }
2279
2280 if (is_postidx) {
2281 int rm = extract32(insn, 16, 5);
2282 if (rm == 31) {
2283 tcg_gen_mov_i64(tcg_rn, tcg_addr);
2284 } else {
2285 tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
2286 }
2287 }
2288 tcg_temp_free_i64(tcg_addr);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002289}
2290
Peter Maydelldf54e472014-01-31 14:47:30 +00002291/* C3.3.3 AdvSIMD load/store single structure
2292 *
2293 * 31 30 29 23 22 21 20 16 15 13 12 11 10 9 5 4 0
2294 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
2295 * | 0 | Q | 0 0 1 1 0 1 0 | L R | 0 0 0 0 0 | opc | S | size | Rn | Rt |
2296 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
2297 *
2298 * C3.3.4 AdvSIMD load/store single structure (post-indexed)
2299 *
2300 * 31 30 29 23 22 21 20 16 15 13 12 11 10 9 5 4 0
2301 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
2302 * | 0 | Q | 0 0 1 1 0 1 1 | L R | Rm | opc | S | size | Rn | Rt |
2303 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
2304 *
2305 * Rt: first (or only) SIMD&FP register to be transferred
2306 * Rn: base address or SP
2307 * Rm (post-index only): post-index register (when !31) or size dependent #imm
2308 * index = encoded in Q:S:size dependent on size
2309 *
2310 * lane_size = encoded in R, opc
2311 * transfer width = encoded in opc, S, size
2312 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002313static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
2314{
Peter Maydelldf54e472014-01-31 14:47:30 +00002315 int rt = extract32(insn, 0, 5);
2316 int rn = extract32(insn, 5, 5);
2317 int size = extract32(insn, 10, 2);
2318 int S = extract32(insn, 12, 1);
2319 int opc = extract32(insn, 13, 3);
2320 int R = extract32(insn, 21, 1);
2321 int is_load = extract32(insn, 22, 1);
2322 int is_postidx = extract32(insn, 23, 1);
2323 int is_q = extract32(insn, 30, 1);
2324
2325 int scale = extract32(opc, 1, 2);
2326 int selem = (extract32(opc, 0, 1) << 1 | R) + 1;
2327 bool replicate = false;
2328 int index = is_q << 3 | S << 2 | size;
2329 int ebytes, xs;
2330 TCGv_i64 tcg_addr, tcg_rn;
2331
2332 switch (scale) {
2333 case 3:
2334 if (!is_load || S) {
2335 unallocated_encoding(s);
2336 return;
2337 }
2338 scale = size;
2339 replicate = true;
2340 break;
2341 case 0:
2342 break;
2343 case 1:
2344 if (extract32(size, 0, 1)) {
2345 unallocated_encoding(s);
2346 return;
2347 }
2348 index >>= 1;
2349 break;
2350 case 2:
2351 if (extract32(size, 1, 1)) {
2352 unallocated_encoding(s);
2353 return;
2354 }
2355 if (!extract32(size, 0, 1)) {
2356 index >>= 2;
2357 } else {
2358 if (S) {
2359 unallocated_encoding(s);
2360 return;
2361 }
2362 index >>= 3;
2363 scale = 3;
2364 }
2365 break;
2366 default:
2367 g_assert_not_reached();
2368 }
2369
2370 ebytes = 1 << scale;
2371
2372 if (rn == 31) {
2373 gen_check_sp_alignment(s);
2374 }
2375
2376 tcg_rn = cpu_reg_sp(s, rn);
2377 tcg_addr = tcg_temp_new_i64();
2378 tcg_gen_mov_i64(tcg_addr, tcg_rn);
2379
2380 for (xs = 0; xs < selem; xs++) {
2381 if (replicate) {
2382 /* Load and replicate to all elements */
2383 uint64_t mulconst;
2384 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
2385
2386 tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr,
2387 get_mem_index(s), MO_TE + scale);
2388 switch (scale) {
2389 case 0:
2390 mulconst = 0x0101010101010101ULL;
2391 break;
2392 case 1:
2393 mulconst = 0x0001000100010001ULL;
2394 break;
2395 case 2:
2396 mulconst = 0x0000000100000001ULL;
2397 break;
2398 case 3:
2399 mulconst = 0;
2400 break;
2401 default:
2402 g_assert_not_reached();
2403 }
2404 if (mulconst) {
2405 tcg_gen_muli_i64(tcg_tmp, tcg_tmp, mulconst);
2406 }
2407 write_vec_element(s, tcg_tmp, rt, 0, MO_64);
2408 if (is_q) {
2409 write_vec_element(s, tcg_tmp, rt, 1, MO_64);
2410 } else {
2411 clear_vec_high(s, rt);
2412 }
2413 tcg_temp_free_i64(tcg_tmp);
2414 } else {
2415 /* Load/store one element per register */
2416 if (is_load) {
2417 do_vec_ld(s, rt, index, tcg_addr, MO_TE + scale);
2418 } else {
2419 do_vec_st(s, rt, index, tcg_addr, MO_TE + scale);
2420 }
2421 }
2422 tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes);
2423 rt = (rt + 1) % 32;
2424 }
2425
2426 if (is_postidx) {
2427 int rm = extract32(insn, 16, 5);
2428 if (rm == 31) {
2429 tcg_gen_mov_i64(tcg_rn, tcg_addr);
2430 } else {
2431 tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
2432 }
2433 }
2434 tcg_temp_free_i64(tcg_addr);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002435}
2436
2437/* C3.3 Loads and stores */
2438static void disas_ldst(DisasContext *s, uint32_t insn)
2439{
2440 switch (extract32(insn, 24, 6)) {
2441 case 0x08: /* Load/store exclusive */
2442 disas_ldst_excl(s, insn);
2443 break;
2444 case 0x18: case 0x1c: /* Load register (literal) */
2445 disas_ld_lit(s, insn);
2446 break;
2447 case 0x28: case 0x29:
2448 case 0x2c: case 0x2d: /* Load/store pair (all forms) */
2449 disas_ldst_pair(s, insn);
2450 break;
2451 case 0x38: case 0x39:
2452 case 0x3c: case 0x3d: /* Load/store register (all forms) */
2453 disas_ldst_reg(s, insn);
2454 break;
2455 case 0x0c: /* AdvSIMD load/store multiple structures */
2456 disas_ldst_multiple_struct(s, insn);
2457 break;
2458 case 0x0d: /* AdvSIMD load/store single structure */
2459 disas_ldst_single_struct(s, insn);
2460 break;
2461 default:
2462 unallocated_encoding(s);
2463 break;
2464 }
2465}
2466
Alexander Graf15bfe8b2013-12-17 19:42:34 +00002467/* C3.4.6 PC-rel. addressing
2468 * 31 30 29 28 24 23 5 4 0
2469 * +----+-------+-----------+-------------------+------+
2470 * | op | immlo | 1 0 0 0 0 | immhi | Rd |
2471 * +----+-------+-----------+-------------------+------+
2472 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002473static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
2474{
Alexander Graf15bfe8b2013-12-17 19:42:34 +00002475 unsigned int page, rd;
2476 uint64_t base;
2477 int64_t offset;
2478
2479 page = extract32(insn, 31, 1);
2480 /* SignExtend(immhi:immlo) -> offset */
2481 offset = ((int64_t)sextract32(insn, 5, 19) << 2) | extract32(insn, 29, 2);
2482 rd = extract32(insn, 0, 5);
2483 base = s->pc - 4;
2484
2485 if (page) {
2486 /* ADRP (page based) */
2487 base &= ~0xfff;
2488 offset <<= 12;
2489 }
2490
2491 tcg_gen_movi_i64(cpu_reg(s, rd), base + offset);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002492}
2493
Alex Bennéeb0ff21b2013-12-23 23:27:29 +00002494/*
2495 * C3.4.1 Add/subtract (immediate)
2496 *
2497 * 31 30 29 28 24 23 22 21 10 9 5 4 0
2498 * +--+--+--+-----------+-----+-------------+-----+-----+
2499 * |sf|op| S| 1 0 0 0 1 |shift| imm12 | Rn | Rd |
2500 * +--+--+--+-----------+-----+-------------+-----+-----+
2501 *
2502 * sf: 0 -> 32bit, 1 -> 64bit
2503 * op: 0 -> add , 1 -> sub
2504 * S: 1 -> set flags
2505 * shift: 00 -> LSL imm by 0, 01 -> LSL imm by 12
2506 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002507static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
2508{
Alex Bennéeb0ff21b2013-12-23 23:27:29 +00002509 int rd = extract32(insn, 0, 5);
2510 int rn = extract32(insn, 5, 5);
2511 uint64_t imm = extract32(insn, 10, 12);
2512 int shift = extract32(insn, 22, 2);
2513 bool setflags = extract32(insn, 29, 1);
2514 bool sub_op = extract32(insn, 30, 1);
2515 bool is_64bit = extract32(insn, 31, 1);
2516
2517 TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
2518 TCGv_i64 tcg_rd = setflags ? cpu_reg(s, rd) : cpu_reg_sp(s, rd);
2519 TCGv_i64 tcg_result;
2520
2521 switch (shift) {
2522 case 0x0:
2523 break;
2524 case 0x1:
2525 imm <<= 12;
2526 break;
2527 default:
2528 unallocated_encoding(s);
2529 return;
2530 }
2531
2532 tcg_result = tcg_temp_new_i64();
2533 if (!setflags) {
2534 if (sub_op) {
2535 tcg_gen_subi_i64(tcg_result, tcg_rn, imm);
2536 } else {
2537 tcg_gen_addi_i64(tcg_result, tcg_rn, imm);
2538 }
2539 } else {
2540 TCGv_i64 tcg_imm = tcg_const_i64(imm);
2541 if (sub_op) {
2542 gen_sub_CC(is_64bit, tcg_result, tcg_rn, tcg_imm);
2543 } else {
2544 gen_add_CC(is_64bit, tcg_result, tcg_rn, tcg_imm);
2545 }
2546 tcg_temp_free_i64(tcg_imm);
2547 }
2548
2549 if (is_64bit) {
2550 tcg_gen_mov_i64(tcg_rd, tcg_result);
2551 } else {
2552 tcg_gen_ext32u_i64(tcg_rd, tcg_result);
2553 }
2554
2555 tcg_temp_free_i64(tcg_result);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002556}
2557
Alexander Graf71b46082013-12-17 19:42:36 +00002558/* The input should be a value in the bottom e bits (with higher
2559 * bits zero); returns that value replicated into every element
2560 * of size e in a 64 bit integer.
2561 */
2562static uint64_t bitfield_replicate(uint64_t mask, unsigned int e)
2563{
2564 assert(e != 0);
2565 while (e < 64) {
2566 mask |= mask << e;
2567 e *= 2;
2568 }
2569 return mask;
2570}
2571
2572/* Return a value with the bottom len bits set (where 0 < len <= 64) */
2573static inline uint64_t bitmask64(unsigned int length)
2574{
2575 assert(length > 0 && length <= 64);
2576 return ~0ULL >> (64 - length);
2577}
2578
2579/* Simplified variant of pseudocode DecodeBitMasks() for the case where we
2580 * only require the wmask. Returns false if the imms/immr/immn are a reserved
2581 * value (ie should cause a guest UNDEF exception), and true if they are
2582 * valid, in which case the decoded bit pattern is written to result.
2583 */
2584static bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
2585 unsigned int imms, unsigned int immr)
2586{
2587 uint64_t mask;
2588 unsigned e, levels, s, r;
2589 int len;
2590
2591 assert(immn < 2 && imms < 64 && immr < 64);
2592
2593 /* The bit patterns we create here are 64 bit patterns which
2594 * are vectors of identical elements of size e = 2, 4, 8, 16, 32 or
2595 * 64 bits each. Each element contains the same value: a run
2596 * of between 1 and e-1 non-zero bits, rotated within the
2597 * element by between 0 and e-1 bits.
2598 *
2599 * The element size and run length are encoded into immn (1 bit)
2600 * and imms (6 bits) as follows:
2601 * 64 bit elements: immn = 1, imms = <length of run - 1>
2602 * 32 bit elements: immn = 0, imms = 0 : <length of run - 1>
2603 * 16 bit elements: immn = 0, imms = 10 : <length of run - 1>
2604 * 8 bit elements: immn = 0, imms = 110 : <length of run - 1>
2605 * 4 bit elements: immn = 0, imms = 1110 : <length of run - 1>
2606 * 2 bit elements: immn = 0, imms = 11110 : <length of run - 1>
2607 * Notice that immn = 0, imms = 11111x is the only combination
2608 * not covered by one of the above options; this is reserved.
2609 * Further, <length of run - 1> all-ones is a reserved pattern.
2610 *
2611 * In all cases the rotation is by immr % e (and immr is 6 bits).
2612 */
2613
2614 /* First determine the element size */
2615 len = 31 - clz32((immn << 6) | (~imms & 0x3f));
2616 if (len < 1) {
2617 /* This is the immn == 0, imms == 0x11111x case */
2618 return false;
2619 }
2620 e = 1 << len;
2621
2622 levels = e - 1;
2623 s = imms & levels;
2624 r = immr & levels;
2625
2626 if (s == levels) {
2627 /* <length of run - 1> mustn't be all-ones. */
2628 return false;
2629 }
2630
2631 /* Create the value of one element: s+1 set bits rotated
2632 * by r within the element (which is e bits wide)...
2633 */
2634 mask = bitmask64(s + 1);
2635 mask = (mask >> r) | (mask << (e - r));
2636 /* ...then replicate the element over the whole 64 bit value */
2637 mask = bitfield_replicate(mask, e);
2638 *result = mask;
2639 return true;
2640}
2641
2642/* C3.4.4 Logical (immediate)
2643 * 31 30 29 28 23 22 21 16 15 10 9 5 4 0
2644 * +----+-----+-------------+---+------+------+------+------+
2645 * | sf | opc | 1 0 0 1 0 0 | N | immr | imms | Rn | Rd |
2646 * +----+-----+-------------+---+------+------+------+------+
2647 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002648static void disas_logic_imm(DisasContext *s, uint32_t insn)
2649{
Alexander Graf71b46082013-12-17 19:42:36 +00002650 unsigned int sf, opc, is_n, immr, imms, rn, rd;
2651 TCGv_i64 tcg_rd, tcg_rn;
2652 uint64_t wmask;
2653 bool is_and = false;
2654
2655 sf = extract32(insn, 31, 1);
2656 opc = extract32(insn, 29, 2);
2657 is_n = extract32(insn, 22, 1);
2658 immr = extract32(insn, 16, 6);
2659 imms = extract32(insn, 10, 6);
2660 rn = extract32(insn, 5, 5);
2661 rd = extract32(insn, 0, 5);
2662
2663 if (!sf && is_n) {
2664 unallocated_encoding(s);
2665 return;
2666 }
2667
2668 if (opc == 0x3) { /* ANDS */
2669 tcg_rd = cpu_reg(s, rd);
2670 } else {
2671 tcg_rd = cpu_reg_sp(s, rd);
2672 }
2673 tcg_rn = cpu_reg(s, rn);
2674
2675 if (!logic_imm_decode_wmask(&wmask, is_n, imms, immr)) {
2676 /* some immediate field values are reserved */
2677 unallocated_encoding(s);
2678 return;
2679 }
2680
2681 if (!sf) {
2682 wmask &= 0xffffffff;
2683 }
2684
2685 switch (opc) {
2686 case 0x3: /* ANDS */
2687 case 0x0: /* AND */
2688 tcg_gen_andi_i64(tcg_rd, tcg_rn, wmask);
2689 is_and = true;
2690 break;
2691 case 0x1: /* ORR */
2692 tcg_gen_ori_i64(tcg_rd, tcg_rn, wmask);
2693 break;
2694 case 0x2: /* EOR */
2695 tcg_gen_xori_i64(tcg_rd, tcg_rn, wmask);
2696 break;
2697 default:
2698 assert(FALSE); /* must handle all above */
2699 break;
2700 }
2701
2702 if (!sf && !is_and) {
2703 /* zero extend final result; we know we can skip this for AND
2704 * since the immediate had the high 32 bits clear.
2705 */
2706 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
2707 }
2708
2709 if (opc == 3) { /* ANDS */
2710 gen_logic_CC(sf, tcg_rd);
2711 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002712}
2713
Alex Bennéeed6ec672013-12-23 23:27:29 +00002714/*
2715 * C3.4.5 Move wide (immediate)
2716 *
2717 * 31 30 29 28 23 22 21 20 5 4 0
2718 * +--+-----+-------------+-----+----------------+------+
2719 * |sf| opc | 1 0 0 1 0 1 | hw | imm16 | Rd |
2720 * +--+-----+-------------+-----+----------------+------+
2721 *
2722 * sf: 0 -> 32 bit, 1 -> 64 bit
2723 * opc: 00 -> N, 10 -> Z, 11 -> K
2724 * hw: shift/16 (0,16, and sf only 32, 48)
2725 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002726static void disas_movw_imm(DisasContext *s, uint32_t insn)
2727{
Alex Bennéeed6ec672013-12-23 23:27:29 +00002728 int rd = extract32(insn, 0, 5);
2729 uint64_t imm = extract32(insn, 5, 16);
2730 int sf = extract32(insn, 31, 1);
2731 int opc = extract32(insn, 29, 2);
2732 int pos = extract32(insn, 21, 2) << 4;
2733 TCGv_i64 tcg_rd = cpu_reg(s, rd);
2734 TCGv_i64 tcg_imm;
2735
2736 if (!sf && (pos >= 32)) {
2737 unallocated_encoding(s);
2738 return;
2739 }
2740
2741 switch (opc) {
2742 case 0: /* MOVN */
2743 case 2: /* MOVZ */
2744 imm <<= pos;
2745 if (opc == 0) {
2746 imm = ~imm;
2747 }
2748 if (!sf) {
2749 imm &= 0xffffffffu;
2750 }
2751 tcg_gen_movi_i64(tcg_rd, imm);
2752 break;
2753 case 3: /* MOVK */
2754 tcg_imm = tcg_const_i64(imm);
2755 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_imm, pos, 16);
2756 tcg_temp_free_i64(tcg_imm);
2757 if (!sf) {
2758 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
2759 }
2760 break;
2761 default:
2762 unallocated_encoding(s);
2763 break;
2764 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002765}
2766
Claudio Fontana88077742013-12-17 19:42:35 +00002767/* C3.4.2 Bitfield
2768 * 31 30 29 28 23 22 21 16 15 10 9 5 4 0
2769 * +----+-----+-------------+---+------+------+------+------+
2770 * | sf | opc | 1 0 0 1 1 0 | N | immr | imms | Rn | Rd |
2771 * +----+-----+-------------+---+------+------+------+------+
2772 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002773static void disas_bitfield(DisasContext *s, uint32_t insn)
2774{
Claudio Fontana88077742013-12-17 19:42:35 +00002775 unsigned int sf, n, opc, ri, si, rn, rd, bitsize, pos, len;
2776 TCGv_i64 tcg_rd, tcg_tmp;
2777
2778 sf = extract32(insn, 31, 1);
2779 opc = extract32(insn, 29, 2);
2780 n = extract32(insn, 22, 1);
2781 ri = extract32(insn, 16, 6);
2782 si = extract32(insn, 10, 6);
2783 rn = extract32(insn, 5, 5);
2784 rd = extract32(insn, 0, 5);
2785 bitsize = sf ? 64 : 32;
2786
2787 if (sf != n || ri >= bitsize || si >= bitsize || opc > 2) {
2788 unallocated_encoding(s);
2789 return;
2790 }
2791
2792 tcg_rd = cpu_reg(s, rd);
2793 tcg_tmp = read_cpu_reg(s, rn, sf);
2794
2795 /* OPTME: probably worth recognizing common cases of ext{8,16,32}{u,s} */
2796
2797 if (opc != 1) { /* SBFM or UBFM */
2798 tcg_gen_movi_i64(tcg_rd, 0);
2799 }
2800
2801 /* do the bit move operation */
2802 if (si >= ri) {
2803 /* Wd<s-r:0> = Wn<s:r> */
2804 tcg_gen_shri_i64(tcg_tmp, tcg_tmp, ri);
2805 pos = 0;
2806 len = (si - ri) + 1;
2807 } else {
2808 /* Wd<32+s-r,32-r> = Wn<s:0> */
2809 pos = bitsize - ri;
2810 len = si + 1;
2811 }
2812
2813 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, pos, len);
2814
2815 if (opc == 0) { /* SBFM - sign extend the destination field */
2816 tcg_gen_shli_i64(tcg_rd, tcg_rd, 64 - (pos + len));
2817 tcg_gen_sari_i64(tcg_rd, tcg_rd, 64 - (pos + len));
2818 }
2819
2820 if (!sf) { /* zero extend final result */
2821 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
2822 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002823}
2824
Alexander Grafe801de92013-12-17 19:42:34 +00002825/* C3.4.3 Extract
2826 * 31 30 29 28 23 22 21 20 16 15 10 9 5 4 0
2827 * +----+------+-------------+---+----+------+--------+------+------+
2828 * | sf | op21 | 1 0 0 1 1 1 | N | o0 | Rm | imms | Rn | Rd |
2829 * +----+------+-------------+---+----+------+--------+------+------+
2830 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002831static void disas_extract(DisasContext *s, uint32_t insn)
2832{
Alexander Grafe801de92013-12-17 19:42:34 +00002833 unsigned int sf, n, rm, imm, rn, rd, bitsize, op21, op0;
2834
2835 sf = extract32(insn, 31, 1);
2836 n = extract32(insn, 22, 1);
2837 rm = extract32(insn, 16, 5);
2838 imm = extract32(insn, 10, 6);
2839 rn = extract32(insn, 5, 5);
2840 rd = extract32(insn, 0, 5);
2841 op21 = extract32(insn, 29, 2);
2842 op0 = extract32(insn, 21, 1);
2843 bitsize = sf ? 64 : 32;
2844
2845 if (sf != n || op21 || op0 || imm >= bitsize) {
2846 unallocated_encoding(s);
2847 } else {
2848 TCGv_i64 tcg_rd, tcg_rm, tcg_rn;
2849
2850 tcg_rd = cpu_reg(s, rd);
2851
2852 if (imm) {
2853 /* OPTME: we can special case rm==rn as a rotate */
2854 tcg_rm = read_cpu_reg(s, rm, sf);
2855 tcg_rn = read_cpu_reg(s, rn, sf);
2856 tcg_gen_shri_i64(tcg_rm, tcg_rm, imm);
2857 tcg_gen_shli_i64(tcg_rn, tcg_rn, bitsize - imm);
2858 tcg_gen_or_i64(tcg_rd, tcg_rm, tcg_rn);
2859 if (!sf) {
2860 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
2861 }
2862 } else {
2863 /* tcg shl_i32/shl_i64 is undefined for 32/64 bit shifts,
2864 * so an extract from bit 0 is a special case.
2865 */
2866 if (sf) {
2867 tcg_gen_mov_i64(tcg_rd, cpu_reg(s, rm));
2868 } else {
2869 tcg_gen_ext32u_i64(tcg_rd, cpu_reg(s, rm));
2870 }
2871 }
2872
2873 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002874}
2875
2876/* C3.4 Data processing - immediate */
2877static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
2878{
2879 switch (extract32(insn, 23, 6)) {
2880 case 0x20: case 0x21: /* PC-rel. addressing */
2881 disas_pc_rel_adr(s, insn);
2882 break;
2883 case 0x22: case 0x23: /* Add/subtract (immediate) */
2884 disas_add_sub_imm(s, insn);
2885 break;
2886 case 0x24: /* Logical (immediate) */
2887 disas_logic_imm(s, insn);
2888 break;
2889 case 0x25: /* Move wide (immediate) */
2890 disas_movw_imm(s, insn);
2891 break;
2892 case 0x26: /* Bitfield */
2893 disas_bitfield(s, insn);
2894 break;
2895 case 0x27: /* Extract */
2896 disas_extract(s, insn);
2897 break;
2898 default:
2899 unallocated_encoding(s);
2900 break;
2901 }
2902}
2903
Alexander Graf832ffa12013-12-17 19:42:34 +00002904/* Shift a TCGv src by TCGv shift_amount, put result in dst.
2905 * Note that it is the caller's responsibility to ensure that the
2906 * shift amount is in range (ie 0..31 or 0..63) and provide the ARM
2907 * mandated semantics for out of range shifts.
2908 */
2909static void shift_reg(TCGv_i64 dst, TCGv_i64 src, int sf,
2910 enum a64_shift_type shift_type, TCGv_i64 shift_amount)
2911{
2912 switch (shift_type) {
2913 case A64_SHIFT_TYPE_LSL:
2914 tcg_gen_shl_i64(dst, src, shift_amount);
2915 break;
2916 case A64_SHIFT_TYPE_LSR:
2917 tcg_gen_shr_i64(dst, src, shift_amount);
2918 break;
2919 case A64_SHIFT_TYPE_ASR:
2920 if (!sf) {
2921 tcg_gen_ext32s_i64(dst, src);
2922 }
2923 tcg_gen_sar_i64(dst, sf ? src : dst, shift_amount);
2924 break;
2925 case A64_SHIFT_TYPE_ROR:
2926 if (sf) {
2927 tcg_gen_rotr_i64(dst, src, shift_amount);
2928 } else {
2929 TCGv_i32 t0, t1;
2930 t0 = tcg_temp_new_i32();
2931 t1 = tcg_temp_new_i32();
2932 tcg_gen_trunc_i64_i32(t0, src);
2933 tcg_gen_trunc_i64_i32(t1, shift_amount);
2934 tcg_gen_rotr_i32(t0, t0, t1);
2935 tcg_gen_extu_i32_i64(dst, t0);
2936 tcg_temp_free_i32(t0);
2937 tcg_temp_free_i32(t1);
2938 }
2939 break;
2940 default:
2941 assert(FALSE); /* all shift types should be handled */
2942 break;
2943 }
2944
2945 if (!sf) { /* zero extend final result */
2946 tcg_gen_ext32u_i64(dst, dst);
2947 }
2948}
2949
2950/* Shift a TCGv src by immediate, put result in dst.
2951 * The shift amount must be in range (this should always be true as the
2952 * relevant instructions will UNDEF on bad shift immediates).
2953 */
2954static void shift_reg_imm(TCGv_i64 dst, TCGv_i64 src, int sf,
2955 enum a64_shift_type shift_type, unsigned int shift_i)
2956{
2957 assert(shift_i < (sf ? 64 : 32));
2958
2959 if (shift_i == 0) {
2960 tcg_gen_mov_i64(dst, src);
2961 } else {
2962 TCGv_i64 shift_const;
2963
2964 shift_const = tcg_const_i64(shift_i);
2965 shift_reg(dst, src, sf, shift_type, shift_const);
2966 tcg_temp_free_i64(shift_const);
2967 }
2968}
2969
2970/* C3.5.10 Logical (shifted register)
2971 * 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0
2972 * +----+-----+-----------+-------+---+------+--------+------+------+
2973 * | sf | opc | 0 1 0 1 0 | shift | N | Rm | imm6 | Rn | Rd |
2974 * +----+-----+-----------+-------+---+------+--------+------+------+
2975 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00002976static void disas_logic_reg(DisasContext *s, uint32_t insn)
2977{
Alexander Graf832ffa12013-12-17 19:42:34 +00002978 TCGv_i64 tcg_rd, tcg_rn, tcg_rm;
2979 unsigned int sf, opc, shift_type, invert, rm, shift_amount, rn, rd;
2980
2981 sf = extract32(insn, 31, 1);
2982 opc = extract32(insn, 29, 2);
2983 shift_type = extract32(insn, 22, 2);
2984 invert = extract32(insn, 21, 1);
2985 rm = extract32(insn, 16, 5);
2986 shift_amount = extract32(insn, 10, 6);
2987 rn = extract32(insn, 5, 5);
2988 rd = extract32(insn, 0, 5);
2989
2990 if (!sf && (shift_amount & (1 << 5))) {
2991 unallocated_encoding(s);
2992 return;
2993 }
2994
2995 tcg_rd = cpu_reg(s, rd);
2996
2997 if (opc == 1 && shift_amount == 0 && shift_type == 0 && rn == 31) {
2998 /* Unshifted ORR and ORN with WZR/XZR is the standard encoding for
2999 * register-register MOV and MVN, so it is worth special casing.
3000 */
3001 tcg_rm = cpu_reg(s, rm);
3002 if (invert) {
3003 tcg_gen_not_i64(tcg_rd, tcg_rm);
3004 if (!sf) {
3005 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3006 }
3007 } else {
3008 if (sf) {
3009 tcg_gen_mov_i64(tcg_rd, tcg_rm);
3010 } else {
3011 tcg_gen_ext32u_i64(tcg_rd, tcg_rm);
3012 }
3013 }
3014 return;
3015 }
3016
3017 tcg_rm = read_cpu_reg(s, rm, sf);
3018
3019 if (shift_amount) {
3020 shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, shift_amount);
3021 }
3022
3023 tcg_rn = cpu_reg(s, rn);
3024
3025 switch (opc | (invert << 2)) {
3026 case 0: /* AND */
3027 case 3: /* ANDS */
3028 tcg_gen_and_i64(tcg_rd, tcg_rn, tcg_rm);
3029 break;
3030 case 1: /* ORR */
3031 tcg_gen_or_i64(tcg_rd, tcg_rn, tcg_rm);
3032 break;
3033 case 2: /* EOR */
3034 tcg_gen_xor_i64(tcg_rd, tcg_rn, tcg_rm);
3035 break;
3036 case 4: /* BIC */
3037 case 7: /* BICS */
3038 tcg_gen_andc_i64(tcg_rd, tcg_rn, tcg_rm);
3039 break;
3040 case 5: /* ORN */
3041 tcg_gen_orc_i64(tcg_rd, tcg_rn, tcg_rm);
3042 break;
3043 case 6: /* EON */
3044 tcg_gen_eqv_i64(tcg_rd, tcg_rn, tcg_rm);
3045 break;
3046 default:
3047 assert(FALSE);
3048 break;
3049 }
3050
3051 if (!sf) {
3052 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3053 }
3054
3055 if (opc == 3) {
3056 gen_logic_CC(sf, tcg_rd);
3057 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003058}
3059
Alex Bennéeb0ff21b2013-12-23 23:27:29 +00003060/*
3061 * C3.5.1 Add/subtract (extended register)
3062 *
3063 * 31|30|29|28 24|23 22|21|20 16|15 13|12 10|9 5|4 0|
3064 * +--+--+--+-----------+-----+--+-------+------+------+----+----+
3065 * |sf|op| S| 0 1 0 1 1 | opt | 1| Rm |option| imm3 | Rn | Rd |
3066 * +--+--+--+-----------+-----+--+-------+------+------+----+----+
3067 *
3068 * sf: 0 -> 32bit, 1 -> 64bit
3069 * op: 0 -> add , 1 -> sub
3070 * S: 1 -> set flags
3071 * opt: 00
3072 * option: extension type (see DecodeRegExtend)
3073 * imm3: optional shift to Rm
3074 *
3075 * Rd = Rn + LSL(extend(Rm), amount)
3076 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003077static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
3078{
Alex Bennéeb0ff21b2013-12-23 23:27:29 +00003079 int rd = extract32(insn, 0, 5);
3080 int rn = extract32(insn, 5, 5);
3081 int imm3 = extract32(insn, 10, 3);
3082 int option = extract32(insn, 13, 3);
3083 int rm = extract32(insn, 16, 5);
3084 bool setflags = extract32(insn, 29, 1);
3085 bool sub_op = extract32(insn, 30, 1);
3086 bool sf = extract32(insn, 31, 1);
3087
3088 TCGv_i64 tcg_rm, tcg_rn; /* temps */
3089 TCGv_i64 tcg_rd;
3090 TCGv_i64 tcg_result;
3091
3092 if (imm3 > 4) {
3093 unallocated_encoding(s);
3094 return;
3095 }
3096
3097 /* non-flag setting ops may use SP */
3098 if (!setflags) {
Alex Bennéeb0ff21b2013-12-23 23:27:29 +00003099 tcg_rd = cpu_reg_sp(s, rd);
3100 } else {
Alex Bennéeb0ff21b2013-12-23 23:27:29 +00003101 tcg_rd = cpu_reg(s, rd);
3102 }
Alex Bennéee201ef72014-02-20 12:46:44 +00003103 tcg_rn = read_cpu_reg_sp(s, rn, sf);
Alex Bennéeb0ff21b2013-12-23 23:27:29 +00003104
3105 tcg_rm = read_cpu_reg(s, rm, sf);
3106 ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3);
3107
3108 tcg_result = tcg_temp_new_i64();
3109
3110 if (!setflags) {
3111 if (sub_op) {
3112 tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
3113 } else {
3114 tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
3115 }
3116 } else {
3117 if (sub_op) {
3118 gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
3119 } else {
3120 gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
3121 }
3122 }
3123
3124 if (sf) {
3125 tcg_gen_mov_i64(tcg_rd, tcg_result);
3126 } else {
3127 tcg_gen_ext32u_i64(tcg_rd, tcg_result);
3128 }
3129
3130 tcg_temp_free_i64(tcg_result);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003131}
3132
Alex Bennéeb0ff21b2013-12-23 23:27:29 +00003133/*
3134 * C3.5.2 Add/subtract (shifted register)
3135 *
3136 * 31 30 29 28 24 23 22 21 20 16 15 10 9 5 4 0
3137 * +--+--+--+-----------+-----+--+-------+---------+------+------+
3138 * |sf|op| S| 0 1 0 1 1 |shift| 0| Rm | imm6 | Rn | Rd |
3139 * +--+--+--+-----------+-----+--+-------+---------+------+------+
3140 *
3141 * sf: 0 -> 32bit, 1 -> 64bit
3142 * op: 0 -> add , 1 -> sub
3143 * S: 1 -> set flags
3144 * shift: 00 -> LSL, 01 -> LSR, 10 -> ASR, 11 -> RESERVED
3145 * imm6: Shift amount to apply to Rm before the add/sub
3146 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003147static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
3148{
Alex Bennéeb0ff21b2013-12-23 23:27:29 +00003149 int rd = extract32(insn, 0, 5);
3150 int rn = extract32(insn, 5, 5);
3151 int imm6 = extract32(insn, 10, 6);
3152 int rm = extract32(insn, 16, 5);
3153 int shift_type = extract32(insn, 22, 2);
3154 bool setflags = extract32(insn, 29, 1);
3155 bool sub_op = extract32(insn, 30, 1);
3156 bool sf = extract32(insn, 31, 1);
3157
3158 TCGv_i64 tcg_rd = cpu_reg(s, rd);
3159 TCGv_i64 tcg_rn, tcg_rm;
3160 TCGv_i64 tcg_result;
3161
3162 if ((shift_type == 3) || (!sf && (imm6 > 31))) {
3163 unallocated_encoding(s);
3164 return;
3165 }
3166
3167 tcg_rn = read_cpu_reg(s, rn, sf);
3168 tcg_rm = read_cpu_reg(s, rm, sf);
3169
3170 shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6);
3171
3172 tcg_result = tcg_temp_new_i64();
3173
3174 if (!setflags) {
3175 if (sub_op) {
3176 tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
3177 } else {
3178 tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
3179 }
3180 } else {
3181 if (sub_op) {
3182 gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
3183 } else {
3184 gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
3185 }
3186 }
3187
3188 if (sf) {
3189 tcg_gen_mov_i64(tcg_rd, tcg_result);
3190 } else {
3191 tcg_gen_ext32u_i64(tcg_rd, tcg_result);
3192 }
3193
3194 tcg_temp_free_i64(tcg_result);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003195}
3196
Alexander Graf52c8b9a2013-12-23 23:27:30 +00003197/* C3.5.9 Data-processing (3 source)
3198
3199 31 30 29 28 24 23 21 20 16 15 14 10 9 5 4 0
3200 +--+------+-----------+------+------+----+------+------+------+
3201 |sf| op54 | 1 1 0 1 1 | op31 | Rm | o0 | Ra | Rn | Rd |
3202 +--+------+-----------+------+------+----+------+------+------+
3203
3204 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003205static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
3206{
Alexander Graf52c8b9a2013-12-23 23:27:30 +00003207 int rd = extract32(insn, 0, 5);
3208 int rn = extract32(insn, 5, 5);
3209 int ra = extract32(insn, 10, 5);
3210 int rm = extract32(insn, 16, 5);
3211 int op_id = (extract32(insn, 29, 3) << 4) |
3212 (extract32(insn, 21, 3) << 1) |
3213 extract32(insn, 15, 1);
3214 bool sf = extract32(insn, 31, 1);
3215 bool is_sub = extract32(op_id, 0, 1);
3216 bool is_high = extract32(op_id, 2, 1);
3217 bool is_signed = false;
3218 TCGv_i64 tcg_op1;
3219 TCGv_i64 tcg_op2;
3220 TCGv_i64 tcg_tmp;
3221
3222 /* Note that op_id is sf:op54:op31:o0 so it includes the 32/64 size flag */
3223 switch (op_id) {
3224 case 0x42: /* SMADDL */
3225 case 0x43: /* SMSUBL */
3226 case 0x44: /* SMULH */
3227 is_signed = true;
3228 break;
3229 case 0x0: /* MADD (32bit) */
3230 case 0x1: /* MSUB (32bit) */
3231 case 0x40: /* MADD (64bit) */
3232 case 0x41: /* MSUB (64bit) */
3233 case 0x4a: /* UMADDL */
3234 case 0x4b: /* UMSUBL */
3235 case 0x4c: /* UMULH */
3236 break;
3237 default:
3238 unallocated_encoding(s);
3239 return;
3240 }
3241
3242 if (is_high) {
3243 TCGv_i64 low_bits = tcg_temp_new_i64(); /* low bits discarded */
3244 TCGv_i64 tcg_rd = cpu_reg(s, rd);
3245 TCGv_i64 tcg_rn = cpu_reg(s, rn);
3246 TCGv_i64 tcg_rm = cpu_reg(s, rm);
3247
3248 if (is_signed) {
3249 tcg_gen_muls2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
3250 } else {
3251 tcg_gen_mulu2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
3252 }
3253
3254 tcg_temp_free_i64(low_bits);
3255 return;
3256 }
3257
3258 tcg_op1 = tcg_temp_new_i64();
3259 tcg_op2 = tcg_temp_new_i64();
3260 tcg_tmp = tcg_temp_new_i64();
3261
3262 if (op_id < 0x42) {
3263 tcg_gen_mov_i64(tcg_op1, cpu_reg(s, rn));
3264 tcg_gen_mov_i64(tcg_op2, cpu_reg(s, rm));
3265 } else {
3266 if (is_signed) {
3267 tcg_gen_ext32s_i64(tcg_op1, cpu_reg(s, rn));
3268 tcg_gen_ext32s_i64(tcg_op2, cpu_reg(s, rm));
3269 } else {
3270 tcg_gen_ext32u_i64(tcg_op1, cpu_reg(s, rn));
3271 tcg_gen_ext32u_i64(tcg_op2, cpu_reg(s, rm));
3272 }
3273 }
3274
3275 if (ra == 31 && !is_sub) {
3276 /* Special-case MADD with rA == XZR; it is the standard MUL alias */
3277 tcg_gen_mul_i64(cpu_reg(s, rd), tcg_op1, tcg_op2);
3278 } else {
3279 tcg_gen_mul_i64(tcg_tmp, tcg_op1, tcg_op2);
3280 if (is_sub) {
3281 tcg_gen_sub_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
3282 } else {
3283 tcg_gen_add_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
3284 }
3285 }
3286
3287 if (!sf) {
3288 tcg_gen_ext32u_i64(cpu_reg(s, rd), cpu_reg(s, rd));
3289 }
3290
3291 tcg_temp_free_i64(tcg_op1);
3292 tcg_temp_free_i64(tcg_op2);
3293 tcg_temp_free_i64(tcg_tmp);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003294}
3295
Claudio Fontana643dbb02014-01-04 22:15:46 +00003296/* C3.5.3 - Add/subtract (with carry)
3297 * 31 30 29 28 27 26 25 24 23 22 21 20 16 15 10 9 5 4 0
3298 * +--+--+--+------------------------+------+---------+------+-----+
3299 * |sf|op| S| 1 1 0 1 0 0 0 0 | rm | opcode2 | Rn | Rd |
3300 * +--+--+--+------------------------+------+---------+------+-----+
3301 * [000000]
3302 */
3303
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003304static void disas_adc_sbc(DisasContext *s, uint32_t insn)
3305{
Claudio Fontana643dbb02014-01-04 22:15:46 +00003306 unsigned int sf, op, setflags, rm, rn, rd;
3307 TCGv_i64 tcg_y, tcg_rn, tcg_rd;
3308
3309 if (extract32(insn, 10, 6) != 0) {
3310 unallocated_encoding(s);
3311 return;
3312 }
3313
3314 sf = extract32(insn, 31, 1);
3315 op = extract32(insn, 30, 1);
3316 setflags = extract32(insn, 29, 1);
3317 rm = extract32(insn, 16, 5);
3318 rn = extract32(insn, 5, 5);
3319 rd = extract32(insn, 0, 5);
3320
3321 tcg_rd = cpu_reg(s, rd);
3322 tcg_rn = cpu_reg(s, rn);
3323
3324 if (op) {
3325 tcg_y = new_tmp_a64(s);
3326 tcg_gen_not_i64(tcg_y, cpu_reg(s, rm));
3327 } else {
3328 tcg_y = cpu_reg(s, rm);
3329 }
3330
3331 if (setflags) {
3332 gen_adc_CC(sf, tcg_rd, tcg_rn, tcg_y);
3333 } else {
3334 gen_adc(sf, tcg_rd, tcg_rn, tcg_y);
3335 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003336}
3337
Claudio Fontana750813c2014-01-04 22:15:46 +00003338/* C3.5.4 - C3.5.5 Conditional compare (immediate / register)
3339 * 31 30 29 28 27 26 25 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0
3340 * +--+--+--+------------------------+--------+------+----+--+------+--+-----+
3341 * |sf|op| S| 1 1 0 1 0 0 1 0 |imm5/rm | cond |i/r |o2| Rn |o3|nzcv |
3342 * +--+--+--+------------------------+--------+------+----+--+------+--+-----+
3343 * [1] y [0] [0]
3344 */
3345static void disas_cc(DisasContext *s, uint32_t insn)
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003346{
Claudio Fontana750813c2014-01-04 22:15:46 +00003347 unsigned int sf, op, y, cond, rn, nzcv, is_imm;
3348 int label_continue = -1;
3349 TCGv_i64 tcg_tmp, tcg_y, tcg_rn;
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003350
Claudio Fontana750813c2014-01-04 22:15:46 +00003351 if (!extract32(insn, 29, 1)) {
3352 unallocated_encoding(s);
3353 return;
3354 }
3355 if (insn & (1 << 10 | 1 << 4)) {
3356 unallocated_encoding(s);
3357 return;
3358 }
3359 sf = extract32(insn, 31, 1);
3360 op = extract32(insn, 30, 1);
3361 is_imm = extract32(insn, 11, 1);
3362 y = extract32(insn, 16, 5); /* y = rm (reg) or imm5 (imm) */
3363 cond = extract32(insn, 12, 4);
3364 rn = extract32(insn, 5, 5);
3365 nzcv = extract32(insn, 0, 4);
3366
3367 if (cond < 0x0e) { /* not always */
3368 int label_match = gen_new_label();
3369 label_continue = gen_new_label();
3370 arm_gen_test_cc(cond, label_match);
3371 /* nomatch: */
3372 tcg_tmp = tcg_temp_new_i64();
3373 tcg_gen_movi_i64(tcg_tmp, nzcv << 28);
3374 gen_set_nzcv(tcg_tmp);
3375 tcg_temp_free_i64(tcg_tmp);
3376 tcg_gen_br(label_continue);
3377 gen_set_label(label_match);
3378 }
3379 /* match, or condition is always */
3380 if (is_imm) {
3381 tcg_y = new_tmp_a64(s);
3382 tcg_gen_movi_i64(tcg_y, y);
3383 } else {
3384 tcg_y = cpu_reg(s, y);
3385 }
3386 tcg_rn = cpu_reg(s, rn);
3387
3388 tcg_tmp = tcg_temp_new_i64();
3389 if (op) {
3390 gen_sub_CC(sf, tcg_tmp, tcg_rn, tcg_y);
3391 } else {
3392 gen_add_CC(sf, tcg_tmp, tcg_rn, tcg_y);
3393 }
3394 tcg_temp_free_i64(tcg_tmp);
3395
3396 if (cond < 0x0e) { /* continue */
3397 gen_set_label(label_continue);
3398 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003399}
3400
Claudio Fontanae952d8c2013-12-17 19:42:33 +00003401/* C3.5.6 Conditional select
3402 * 31 30 29 28 21 20 16 15 12 11 10 9 5 4 0
3403 * +----+----+---+-----------------+------+------+-----+------+------+
3404 * | sf | op | S | 1 1 0 1 0 1 0 0 | Rm | cond | op2 | Rn | Rd |
3405 * +----+----+---+-----------------+------+------+-----+------+------+
3406 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003407static void disas_cond_select(DisasContext *s, uint32_t insn)
3408{
Claudio Fontanae952d8c2013-12-17 19:42:33 +00003409 unsigned int sf, else_inv, rm, cond, else_inc, rn, rd;
3410 TCGv_i64 tcg_rd, tcg_src;
3411
3412 if (extract32(insn, 29, 1) || extract32(insn, 11, 1)) {
3413 /* S == 1 or op2<1> == 1 */
3414 unallocated_encoding(s);
3415 return;
3416 }
3417 sf = extract32(insn, 31, 1);
3418 else_inv = extract32(insn, 30, 1);
3419 rm = extract32(insn, 16, 5);
3420 cond = extract32(insn, 12, 4);
3421 else_inc = extract32(insn, 10, 1);
3422 rn = extract32(insn, 5, 5);
3423 rd = extract32(insn, 0, 5);
3424
3425 if (rd == 31) {
3426 /* silly no-op write; until we use movcond we must special-case
3427 * this to avoid a dead temporary across basic blocks.
3428 */
3429 return;
3430 }
3431
3432 tcg_rd = cpu_reg(s, rd);
3433
3434 if (cond >= 0x0e) { /* condition "always" */
3435 tcg_src = read_cpu_reg(s, rn, sf);
3436 tcg_gen_mov_i64(tcg_rd, tcg_src);
3437 } else {
3438 /* OPTME: we could use movcond here, at the cost of duplicating
3439 * a lot of the arm_gen_test_cc() logic.
3440 */
3441 int label_match = gen_new_label();
3442 int label_continue = gen_new_label();
3443
3444 arm_gen_test_cc(cond, label_match);
3445 /* nomatch: */
3446 tcg_src = cpu_reg(s, rm);
3447
3448 if (else_inv && else_inc) {
3449 tcg_gen_neg_i64(tcg_rd, tcg_src);
3450 } else if (else_inv) {
3451 tcg_gen_not_i64(tcg_rd, tcg_src);
3452 } else if (else_inc) {
3453 tcg_gen_addi_i64(tcg_rd, tcg_src, 1);
3454 } else {
3455 tcg_gen_mov_i64(tcg_rd, tcg_src);
3456 }
3457 if (!sf) {
3458 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3459 }
3460 tcg_gen_br(label_continue);
3461 /* match: */
3462 gen_set_label(label_match);
3463 tcg_src = read_cpu_reg(s, rn, sf);
3464 tcg_gen_mov_i64(tcg_rd, tcg_src);
3465 /* continue: */
3466 gen_set_label(label_continue);
3467 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003468}
3469
Claudio Fontana680ead22013-12-17 19:42:35 +00003470static void handle_clz(DisasContext *s, unsigned int sf,
3471 unsigned int rn, unsigned int rd)
3472{
3473 TCGv_i64 tcg_rd, tcg_rn;
3474 tcg_rd = cpu_reg(s, rd);
3475 tcg_rn = cpu_reg(s, rn);
3476
3477 if (sf) {
3478 gen_helper_clz64(tcg_rd, tcg_rn);
3479 } else {
3480 TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
3481 tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
3482 gen_helper_clz(tcg_tmp32, tcg_tmp32);
3483 tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
3484 tcg_temp_free_i32(tcg_tmp32);
3485 }
3486}
3487
Claudio Fontanae80c5022013-12-17 19:42:35 +00003488static void handle_cls(DisasContext *s, unsigned int sf,
3489 unsigned int rn, unsigned int rd)
3490{
3491 TCGv_i64 tcg_rd, tcg_rn;
3492 tcg_rd = cpu_reg(s, rd);
3493 tcg_rn = cpu_reg(s, rn);
3494
3495 if (sf) {
3496 gen_helper_cls64(tcg_rd, tcg_rn);
3497 } else {
3498 TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
3499 tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
3500 gen_helper_cls32(tcg_tmp32, tcg_tmp32);
3501 tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
3502 tcg_temp_free_i32(tcg_tmp32);
3503 }
3504}
3505
Alexander Graf82e14b02013-12-17 19:42:35 +00003506static void handle_rbit(DisasContext *s, unsigned int sf,
3507 unsigned int rn, unsigned int rd)
3508{
3509 TCGv_i64 tcg_rd, tcg_rn;
3510 tcg_rd = cpu_reg(s, rd);
3511 tcg_rn = cpu_reg(s, rn);
3512
3513 if (sf) {
3514 gen_helper_rbit64(tcg_rd, tcg_rn);
3515 } else {
3516 TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
3517 tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
3518 gen_helper_rbit(tcg_tmp32, tcg_tmp32);
3519 tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
3520 tcg_temp_free_i32(tcg_tmp32);
3521 }
3522}
3523
Claudio Fontana45323202013-12-17 19:42:35 +00003524/* C5.6.149 REV with sf==1, opcode==3 ("REV64") */
3525static void handle_rev64(DisasContext *s, unsigned int sf,
3526 unsigned int rn, unsigned int rd)
3527{
3528 if (!sf) {
3529 unallocated_encoding(s);
3530 return;
3531 }
3532 tcg_gen_bswap64_i64(cpu_reg(s, rd), cpu_reg(s, rn));
3533}
3534
3535/* C5.6.149 REV with sf==0, opcode==2
3536 * C5.6.151 REV32 (sf==1, opcode==2)
3537 */
3538static void handle_rev32(DisasContext *s, unsigned int sf,
3539 unsigned int rn, unsigned int rd)
3540{
3541 TCGv_i64 tcg_rd = cpu_reg(s, rd);
3542
3543 if (sf) {
3544 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
3545 TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
3546
3547 /* bswap32_i64 requires zero high word */
3548 tcg_gen_ext32u_i64(tcg_tmp, tcg_rn);
3549 tcg_gen_bswap32_i64(tcg_rd, tcg_tmp);
3550 tcg_gen_shri_i64(tcg_tmp, tcg_rn, 32);
3551 tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp);
3552 tcg_gen_concat32_i64(tcg_rd, tcg_rd, tcg_tmp);
3553
3554 tcg_temp_free_i64(tcg_tmp);
3555 } else {
3556 tcg_gen_ext32u_i64(tcg_rd, cpu_reg(s, rn));
3557 tcg_gen_bswap32_i64(tcg_rd, tcg_rd);
3558 }
3559}
3560
3561/* C5.6.150 REV16 (opcode==1) */
3562static void handle_rev16(DisasContext *s, unsigned int sf,
3563 unsigned int rn, unsigned int rd)
3564{
3565 TCGv_i64 tcg_rd = cpu_reg(s, rd);
3566 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
3567 TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
3568
3569 tcg_gen_andi_i64(tcg_tmp, tcg_rn, 0xffff);
3570 tcg_gen_bswap16_i64(tcg_rd, tcg_tmp);
3571
3572 tcg_gen_shri_i64(tcg_tmp, tcg_rn, 16);
3573 tcg_gen_andi_i64(tcg_tmp, tcg_tmp, 0xffff);
3574 tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
3575 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, 16, 16);
3576
3577 if (sf) {
3578 tcg_gen_shri_i64(tcg_tmp, tcg_rn, 32);
3579 tcg_gen_andi_i64(tcg_tmp, tcg_tmp, 0xffff);
3580 tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
3581 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, 32, 16);
3582
3583 tcg_gen_shri_i64(tcg_tmp, tcg_rn, 48);
3584 tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
3585 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, 48, 16);
3586 }
3587
3588 tcg_temp_free_i64(tcg_tmp);
3589}
3590
Claudio Fontana680ead22013-12-17 19:42:35 +00003591/* C3.5.7 Data-processing (1 source)
3592 * 31 30 29 28 21 20 16 15 10 9 5 4 0
3593 * +----+---+---+-----------------+---------+--------+------+------+
3594 * | sf | 1 | S | 1 1 0 1 0 1 1 0 | opcode2 | opcode | Rn | Rd |
3595 * +----+---+---+-----------------+---------+--------+------+------+
3596 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003597static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
3598{
Claudio Fontana680ead22013-12-17 19:42:35 +00003599 unsigned int sf, opcode, rn, rd;
3600
3601 if (extract32(insn, 29, 1) || extract32(insn, 16, 5)) {
3602 unallocated_encoding(s);
3603 return;
3604 }
3605
3606 sf = extract32(insn, 31, 1);
3607 opcode = extract32(insn, 10, 6);
3608 rn = extract32(insn, 5, 5);
3609 rd = extract32(insn, 0, 5);
3610
3611 switch (opcode) {
3612 case 0: /* RBIT */
Alexander Graf82e14b02013-12-17 19:42:35 +00003613 handle_rbit(s, sf, rn, rd);
3614 break;
Claudio Fontana680ead22013-12-17 19:42:35 +00003615 case 1: /* REV16 */
Claudio Fontana45323202013-12-17 19:42:35 +00003616 handle_rev16(s, sf, rn, rd);
3617 break;
Claudio Fontana680ead22013-12-17 19:42:35 +00003618 case 2: /* REV32 */
Claudio Fontana45323202013-12-17 19:42:35 +00003619 handle_rev32(s, sf, rn, rd);
3620 break;
Claudio Fontana680ead22013-12-17 19:42:35 +00003621 case 3: /* REV64 */
Claudio Fontana45323202013-12-17 19:42:35 +00003622 handle_rev64(s, sf, rn, rd);
Claudio Fontana680ead22013-12-17 19:42:35 +00003623 break;
3624 case 4: /* CLZ */
3625 handle_clz(s, sf, rn, rd);
3626 break;
3627 case 5: /* CLS */
Claudio Fontanae80c5022013-12-17 19:42:35 +00003628 handle_cls(s, sf, rn, rd);
Claudio Fontana680ead22013-12-17 19:42:35 +00003629 break;
3630 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003631}
3632
Alexander Graf8220e912013-12-17 19:42:34 +00003633static void handle_div(DisasContext *s, bool is_signed, unsigned int sf,
3634 unsigned int rm, unsigned int rn, unsigned int rd)
3635{
3636 TCGv_i64 tcg_n, tcg_m, tcg_rd;
3637 tcg_rd = cpu_reg(s, rd);
3638
3639 if (!sf && is_signed) {
3640 tcg_n = new_tmp_a64(s);
3641 tcg_m = new_tmp_a64(s);
3642 tcg_gen_ext32s_i64(tcg_n, cpu_reg(s, rn));
3643 tcg_gen_ext32s_i64(tcg_m, cpu_reg(s, rm));
3644 } else {
3645 tcg_n = read_cpu_reg(s, rn, sf);
3646 tcg_m = read_cpu_reg(s, rm, sf);
3647 }
3648
3649 if (is_signed) {
3650 gen_helper_sdiv64(tcg_rd, tcg_n, tcg_m);
3651 } else {
3652 gen_helper_udiv64(tcg_rd, tcg_n, tcg_m);
3653 }
3654
3655 if (!sf) { /* zero extend final result */
3656 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3657 }
3658}
3659
Alexander Graf6c1adc92013-12-17 19:42:34 +00003660/* C5.6.115 LSLV, C5.6.118 LSRV, C5.6.17 ASRV, C5.6.154 RORV */
3661static void handle_shift_reg(DisasContext *s,
3662 enum a64_shift_type shift_type, unsigned int sf,
3663 unsigned int rm, unsigned int rn, unsigned int rd)
3664{
3665 TCGv_i64 tcg_shift = tcg_temp_new_i64();
3666 TCGv_i64 tcg_rd = cpu_reg(s, rd);
3667 TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
3668
3669 tcg_gen_andi_i64(tcg_shift, cpu_reg(s, rm), sf ? 63 : 31);
3670 shift_reg(tcg_rd, tcg_rn, sf, shift_type, tcg_shift);
3671 tcg_temp_free_i64(tcg_shift);
3672}
3673
Alexander Graf8220e912013-12-17 19:42:34 +00003674/* C3.5.8 Data-processing (2 source)
3675 * 31 30 29 28 21 20 16 15 10 9 5 4 0
3676 * +----+---+---+-----------------+------+--------+------+------+
3677 * | sf | 0 | S | 1 1 0 1 0 1 1 0 | Rm | opcode | Rn | Rd |
3678 * +----+---+---+-----------------+------+--------+------+------+
3679 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003680static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
3681{
Alexander Graf8220e912013-12-17 19:42:34 +00003682 unsigned int sf, rm, opcode, rn, rd;
3683 sf = extract32(insn, 31, 1);
3684 rm = extract32(insn, 16, 5);
3685 opcode = extract32(insn, 10, 6);
3686 rn = extract32(insn, 5, 5);
3687 rd = extract32(insn, 0, 5);
3688
3689 if (extract32(insn, 29, 1)) {
3690 unallocated_encoding(s);
3691 return;
3692 }
3693
3694 switch (opcode) {
3695 case 2: /* UDIV */
3696 handle_div(s, false, sf, rm, rn, rd);
3697 break;
3698 case 3: /* SDIV */
3699 handle_div(s, true, sf, rm, rn, rd);
3700 break;
3701 case 8: /* LSLV */
Alexander Graf6c1adc92013-12-17 19:42:34 +00003702 handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd);
3703 break;
Alexander Graf8220e912013-12-17 19:42:34 +00003704 case 9: /* LSRV */
Alexander Graf6c1adc92013-12-17 19:42:34 +00003705 handle_shift_reg(s, A64_SHIFT_TYPE_LSR, sf, rm, rn, rd);
3706 break;
Alexander Graf8220e912013-12-17 19:42:34 +00003707 case 10: /* ASRV */
Alexander Graf6c1adc92013-12-17 19:42:34 +00003708 handle_shift_reg(s, A64_SHIFT_TYPE_ASR, sf, rm, rn, rd);
3709 break;
Alexander Graf8220e912013-12-17 19:42:34 +00003710 case 11: /* RORV */
Alexander Graf6c1adc92013-12-17 19:42:34 +00003711 handle_shift_reg(s, A64_SHIFT_TYPE_ROR, sf, rm, rn, rd);
3712 break;
Alexander Graf8220e912013-12-17 19:42:34 +00003713 case 16:
3714 case 17:
3715 case 18:
3716 case 19:
3717 case 20:
3718 case 21:
3719 case 22:
3720 case 23: /* CRC32 */
3721 unsupported_encoding(s, insn);
3722 break;
3723 default:
3724 unallocated_encoding(s);
3725 break;
3726 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003727}
3728
3729/* C3.5 Data processing - register */
3730static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
3731{
3732 switch (extract32(insn, 24, 5)) {
3733 case 0x0a: /* Logical (shifted register) */
3734 disas_logic_reg(s, insn);
3735 break;
3736 case 0x0b: /* Add/subtract */
3737 if (insn & (1 << 21)) { /* (extended register) */
3738 disas_add_sub_ext_reg(s, insn);
3739 } else {
3740 disas_add_sub_reg(s, insn);
3741 }
3742 break;
3743 case 0x1b: /* Data-processing (3 source) */
3744 disas_data_proc_3src(s, insn);
3745 break;
3746 case 0x1a:
3747 switch (extract32(insn, 21, 3)) {
3748 case 0x0: /* Add/subtract (with carry) */
3749 disas_adc_sbc(s, insn);
3750 break;
3751 case 0x2: /* Conditional compare */
Claudio Fontana750813c2014-01-04 22:15:46 +00003752 disas_cc(s, insn); /* both imm and reg forms */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00003753 break;
3754 case 0x4: /* Conditional select */
3755 disas_cond_select(s, insn);
3756 break;
3757 case 0x6: /* Data-processing */
3758 if (insn & (1 << 30)) { /* (1 source) */
3759 disas_data_proc_1src(s, insn);
3760 } else { /* (2 source) */
3761 disas_data_proc_2src(s, insn);
3762 }
3763 break;
3764 default:
3765 unallocated_encoding(s);
3766 break;
3767 }
3768 break;
3769 default:
3770 unallocated_encoding(s);
3771 break;
3772 }
3773}
3774
Claudio Fontanada7dafe2014-01-04 22:15:50 +00003775static void handle_fp_compare(DisasContext *s, bool is_double,
3776 unsigned int rn, unsigned int rm,
3777 bool cmp_with_zero, bool signal_all_nans)
3778{
3779 TCGv_i64 tcg_flags = tcg_temp_new_i64();
3780 TCGv_ptr fpst = get_fpstatus_ptr();
3781
3782 if (is_double) {
3783 TCGv_i64 tcg_vn, tcg_vm;
3784
3785 tcg_vn = read_fp_dreg(s, rn);
3786 if (cmp_with_zero) {
3787 tcg_vm = tcg_const_i64(0);
3788 } else {
3789 tcg_vm = read_fp_dreg(s, rm);
3790 }
3791 if (signal_all_nans) {
3792 gen_helper_vfp_cmped_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
3793 } else {
3794 gen_helper_vfp_cmpd_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
3795 }
3796 tcg_temp_free_i64(tcg_vn);
3797 tcg_temp_free_i64(tcg_vm);
3798 } else {
3799 TCGv_i32 tcg_vn, tcg_vm;
3800
3801 tcg_vn = read_fp_sreg(s, rn);
3802 if (cmp_with_zero) {
3803 tcg_vm = tcg_const_i32(0);
3804 } else {
3805 tcg_vm = read_fp_sreg(s, rm);
3806 }
3807 if (signal_all_nans) {
3808 gen_helper_vfp_cmpes_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
3809 } else {
3810 gen_helper_vfp_cmps_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
3811 }
3812 tcg_temp_free_i32(tcg_vn);
3813 tcg_temp_free_i32(tcg_vm);
3814 }
3815
3816 tcg_temp_free_ptr(fpst);
3817
3818 gen_set_nzcv(tcg_flags);
3819
3820 tcg_temp_free_i64(tcg_flags);
3821}
3822
Peter Maydellfaa0ba42013-12-23 23:27:30 +00003823/* C3.6.22 Floating point compare
3824 * 31 30 29 28 24 23 22 21 20 16 15 14 13 10 9 5 4 0
3825 * +---+---+---+-----------+------+---+------+-----+---------+------+-------+
3826 * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | op | 1 0 0 0 | Rn | op2 |
3827 * +---+---+---+-----------+------+---+------+-----+---------+------+-------+
3828 */
3829static void disas_fp_compare(DisasContext *s, uint32_t insn)
3830{
Claudio Fontanada7dafe2014-01-04 22:15:50 +00003831 unsigned int mos, type, rm, op, rn, opc, op2r;
3832
3833 mos = extract32(insn, 29, 3);
3834 type = extract32(insn, 22, 2); /* 0 = single, 1 = double */
3835 rm = extract32(insn, 16, 5);
3836 op = extract32(insn, 14, 2);
3837 rn = extract32(insn, 5, 5);
3838 opc = extract32(insn, 3, 2);
3839 op2r = extract32(insn, 0, 3);
3840
3841 if (mos || op || op2r || type > 1) {
3842 unallocated_encoding(s);
3843 return;
3844 }
3845
3846 handle_fp_compare(s, type, rn, rm, opc & 1, opc & 2);
Peter Maydellfaa0ba42013-12-23 23:27:30 +00003847}
3848
3849/* C3.6.23 Floating point conditional compare
3850 * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0
3851 * +---+---+---+-----------+------+---+------+------+-----+------+----+------+
3852 * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | cond | 0 1 | Rn | op | nzcv |
3853 * +---+---+---+-----------+------+---+------+------+-----+------+----+------+
3854 */
3855static void disas_fp_ccomp(DisasContext *s, uint32_t insn)
3856{
Claudio Fontana513f1d72014-01-04 22:15:51 +00003857 unsigned int mos, type, rm, cond, rn, op, nzcv;
3858 TCGv_i64 tcg_flags;
3859 int label_continue = -1;
3860
3861 mos = extract32(insn, 29, 3);
3862 type = extract32(insn, 22, 2); /* 0 = single, 1 = double */
3863 rm = extract32(insn, 16, 5);
3864 cond = extract32(insn, 12, 4);
3865 rn = extract32(insn, 5, 5);
3866 op = extract32(insn, 4, 1);
3867 nzcv = extract32(insn, 0, 4);
3868
3869 if (mos || type > 1) {
3870 unallocated_encoding(s);
3871 return;
3872 }
3873
3874 if (cond < 0x0e) { /* not always */
3875 int label_match = gen_new_label();
3876 label_continue = gen_new_label();
3877 arm_gen_test_cc(cond, label_match);
3878 /* nomatch: */
3879 tcg_flags = tcg_const_i64(nzcv << 28);
3880 gen_set_nzcv(tcg_flags);
3881 tcg_temp_free_i64(tcg_flags);
3882 tcg_gen_br(label_continue);
3883 gen_set_label(label_match);
3884 }
3885
3886 handle_fp_compare(s, type, rn, rm, false, op);
3887
3888 if (cond < 0x0e) {
3889 gen_set_label(label_continue);
3890 }
Peter Maydellfaa0ba42013-12-23 23:27:30 +00003891}
3892
Claudio Fontana5640ff62014-01-04 22:15:51 +00003893/* copy src FP register to dst FP register; type specifies single or double */
3894static void gen_mov_fp2fp(DisasContext *s, int type, int dst, int src)
3895{
3896 if (type) {
3897 TCGv_i64 v = read_fp_dreg(s, src);
3898 write_fp_dreg(s, dst, v);
3899 tcg_temp_free_i64(v);
3900 } else {
3901 TCGv_i32 v = read_fp_sreg(s, src);
3902 write_fp_sreg(s, dst, v);
3903 tcg_temp_free_i32(v);
3904 }
3905}
3906
Peter Maydellfaa0ba42013-12-23 23:27:30 +00003907/* C3.6.24 Floating point conditional select
3908 * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
3909 * +---+---+---+-----------+------+---+------+------+-----+------+------+
3910 * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | cond | 1 1 | Rn | Rd |
3911 * +---+---+---+-----------+------+---+------+------+-----+------+------+
3912 */
3913static void disas_fp_csel(DisasContext *s, uint32_t insn)
3914{
Claudio Fontana5640ff62014-01-04 22:15:51 +00003915 unsigned int mos, type, rm, cond, rn, rd;
3916 int label_continue = -1;
3917
3918 mos = extract32(insn, 29, 3);
3919 type = extract32(insn, 22, 2); /* 0 = single, 1 = double */
3920 rm = extract32(insn, 16, 5);
3921 cond = extract32(insn, 12, 4);
3922 rn = extract32(insn, 5, 5);
3923 rd = extract32(insn, 0, 5);
3924
3925 if (mos || type > 1) {
3926 unallocated_encoding(s);
3927 return;
3928 }
3929
3930 if (cond < 0x0e) { /* not always */
3931 int label_match = gen_new_label();
3932 label_continue = gen_new_label();
3933 arm_gen_test_cc(cond, label_match);
3934 /* nomatch: */
3935 gen_mov_fp2fp(s, type, rd, rm);
3936 tcg_gen_br(label_continue);
3937 gen_set_label(label_match);
3938 }
3939
3940 gen_mov_fp2fp(s, type, rd, rn);
3941
3942 if (cond < 0x0e) { /* continue */
3943 gen_set_label(label_continue);
3944 }
Peter Maydellfaa0ba42013-12-23 23:27:30 +00003945}
3946
Peter Maydelld9b08482014-01-07 17:19:14 +00003947/* C3.6.25 Floating-point data-processing (1 source) - single precision */
3948static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
3949{
3950 TCGv_ptr fpst;
3951 TCGv_i32 tcg_op;
3952 TCGv_i32 tcg_res;
3953
3954 fpst = get_fpstatus_ptr();
3955 tcg_op = read_fp_sreg(s, rn);
3956 tcg_res = tcg_temp_new_i32();
3957
3958 switch (opcode) {
3959 case 0x0: /* FMOV */
3960 tcg_gen_mov_i32(tcg_res, tcg_op);
3961 break;
3962 case 0x1: /* FABS */
3963 gen_helper_vfp_abss(tcg_res, tcg_op);
3964 break;
3965 case 0x2: /* FNEG */
3966 gen_helper_vfp_negs(tcg_res, tcg_op);
3967 break;
3968 case 0x3: /* FSQRT */
3969 gen_helper_vfp_sqrts(tcg_res, tcg_op, cpu_env);
3970 break;
3971 case 0x8: /* FRINTN */
3972 case 0x9: /* FRINTP */
3973 case 0xa: /* FRINTM */
3974 case 0xb: /* FRINTZ */
3975 case 0xc: /* FRINTA */
3976 {
3977 TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
3978
3979 gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
3980 gen_helper_rints(tcg_res, tcg_op, fpst);
3981
3982 gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
3983 tcg_temp_free_i32(tcg_rmode);
3984 break;
3985 }
3986 case 0xe: /* FRINTX */
3987 gen_helper_rints_exact(tcg_res, tcg_op, fpst);
3988 break;
3989 case 0xf: /* FRINTI */
3990 gen_helper_rints(tcg_res, tcg_op, fpst);
3991 break;
3992 default:
3993 abort();
3994 }
3995
3996 write_fp_sreg(s, rd, tcg_res);
3997
3998 tcg_temp_free_ptr(fpst);
3999 tcg_temp_free_i32(tcg_op);
4000 tcg_temp_free_i32(tcg_res);
4001}
4002
4003/* C3.6.25 Floating-point data-processing (1 source) - double precision */
4004static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
4005{
4006 TCGv_ptr fpst;
4007 TCGv_i64 tcg_op;
4008 TCGv_i64 tcg_res;
4009
4010 fpst = get_fpstatus_ptr();
4011 tcg_op = read_fp_dreg(s, rn);
4012 tcg_res = tcg_temp_new_i64();
4013
4014 switch (opcode) {
4015 case 0x0: /* FMOV */
4016 tcg_gen_mov_i64(tcg_res, tcg_op);
4017 break;
4018 case 0x1: /* FABS */
4019 gen_helper_vfp_absd(tcg_res, tcg_op);
4020 break;
4021 case 0x2: /* FNEG */
4022 gen_helper_vfp_negd(tcg_res, tcg_op);
4023 break;
4024 case 0x3: /* FSQRT */
4025 gen_helper_vfp_sqrtd(tcg_res, tcg_op, cpu_env);
4026 break;
4027 case 0x8: /* FRINTN */
4028 case 0x9: /* FRINTP */
4029 case 0xa: /* FRINTM */
4030 case 0xb: /* FRINTZ */
4031 case 0xc: /* FRINTA */
4032 {
4033 TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
4034
4035 gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
4036 gen_helper_rintd(tcg_res, tcg_op, fpst);
4037
4038 gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
4039 tcg_temp_free_i32(tcg_rmode);
4040 break;
4041 }
4042 case 0xe: /* FRINTX */
4043 gen_helper_rintd_exact(tcg_res, tcg_op, fpst);
4044 break;
4045 case 0xf: /* FRINTI */
4046 gen_helper_rintd(tcg_res, tcg_op, fpst);
4047 break;
4048 default:
4049 abort();
4050 }
4051
4052 write_fp_dreg(s, rd, tcg_res);
4053
4054 tcg_temp_free_ptr(fpst);
4055 tcg_temp_free_i64(tcg_op);
4056 tcg_temp_free_i64(tcg_res);
4057}
4058
Peter Maydell8900aad2014-01-07 17:19:15 +00004059static void handle_fp_fcvt(DisasContext *s, int opcode,
4060 int rd, int rn, int dtype, int ntype)
4061{
4062 switch (ntype) {
4063 case 0x0:
4064 {
4065 TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
4066 if (dtype == 1) {
4067 /* Single to double */
4068 TCGv_i64 tcg_rd = tcg_temp_new_i64();
4069 gen_helper_vfp_fcvtds(tcg_rd, tcg_rn, cpu_env);
4070 write_fp_dreg(s, rd, tcg_rd);
4071 tcg_temp_free_i64(tcg_rd);
4072 } else {
4073 /* Single to half */
4074 TCGv_i32 tcg_rd = tcg_temp_new_i32();
4075 gen_helper_vfp_fcvt_f32_to_f16(tcg_rd, tcg_rn, cpu_env);
4076 /* write_fp_sreg is OK here because top half of tcg_rd is zero */
4077 write_fp_sreg(s, rd, tcg_rd);
4078 tcg_temp_free_i32(tcg_rd);
4079 }
4080 tcg_temp_free_i32(tcg_rn);
4081 break;
4082 }
4083 case 0x1:
4084 {
4085 TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
4086 TCGv_i32 tcg_rd = tcg_temp_new_i32();
4087 if (dtype == 0) {
4088 /* Double to single */
4089 gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, cpu_env);
4090 } else {
4091 /* Double to half */
4092 gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, cpu_env);
4093 /* write_fp_sreg is OK here because top half of tcg_rd is zero */
4094 }
4095 write_fp_sreg(s, rd, tcg_rd);
4096 tcg_temp_free_i32(tcg_rd);
4097 tcg_temp_free_i64(tcg_rn);
4098 break;
4099 }
4100 case 0x3:
4101 {
4102 TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
4103 tcg_gen_ext16u_i32(tcg_rn, tcg_rn);
4104 if (dtype == 0) {
4105 /* Half to single */
4106 TCGv_i32 tcg_rd = tcg_temp_new_i32();
4107 gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, cpu_env);
4108 write_fp_sreg(s, rd, tcg_rd);
4109 tcg_temp_free_i32(tcg_rd);
4110 } else {
4111 /* Half to double */
4112 TCGv_i64 tcg_rd = tcg_temp_new_i64();
4113 gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, cpu_env);
4114 write_fp_dreg(s, rd, tcg_rd);
4115 tcg_temp_free_i64(tcg_rd);
4116 }
4117 tcg_temp_free_i32(tcg_rn);
4118 break;
4119 }
4120 default:
4121 abort();
4122 }
4123}
4124
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004125/* C3.6.25 Floating point data-processing (1 source)
4126 * 31 30 29 28 24 23 22 21 20 15 14 10 9 5 4 0
4127 * +---+---+---+-----------+------+---+--------+-----------+------+------+
4128 * | M | 0 | S | 1 1 1 1 0 | type | 1 | opcode | 1 0 0 0 0 | Rn | Rd |
4129 * +---+---+---+-----------+------+---+--------+-----------+------+------+
4130 */
4131static void disas_fp_1src(DisasContext *s, uint32_t insn)
4132{
Peter Maydelld9b08482014-01-07 17:19:14 +00004133 int type = extract32(insn, 22, 2);
4134 int opcode = extract32(insn, 15, 6);
4135 int rn = extract32(insn, 5, 5);
4136 int rd = extract32(insn, 0, 5);
4137
4138 switch (opcode) {
4139 case 0x4: case 0x5: case 0x7:
Peter Maydell8900aad2014-01-07 17:19:15 +00004140 {
Peter Maydelld9b08482014-01-07 17:19:14 +00004141 /* FCVT between half, single and double precision */
Peter Maydell8900aad2014-01-07 17:19:15 +00004142 int dtype = extract32(opcode, 0, 2);
4143 if (type == 2 || dtype == type) {
4144 unallocated_encoding(s);
4145 return;
4146 }
4147 handle_fp_fcvt(s, opcode, rd, rn, dtype, type);
Peter Maydelld9b08482014-01-07 17:19:14 +00004148 break;
Peter Maydell8900aad2014-01-07 17:19:15 +00004149 }
Peter Maydelld9b08482014-01-07 17:19:14 +00004150 case 0x0 ... 0x3:
4151 case 0x8 ... 0xc:
4152 case 0xe ... 0xf:
4153 /* 32-to-32 and 64-to-64 ops */
4154 switch (type) {
4155 case 0:
4156 handle_fp_1src_single(s, opcode, rd, rn);
4157 break;
4158 case 1:
4159 handle_fp_1src_double(s, opcode, rd, rn);
4160 break;
4161 default:
4162 unallocated_encoding(s);
4163 }
4164 break;
4165 default:
4166 unallocated_encoding(s);
4167 break;
4168 }
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004169}
4170
Alexander Grafec73d2e2014-01-04 22:15:50 +00004171/* C3.6.26 Floating-point data-processing (2 source) - single precision */
4172static void handle_fp_2src_single(DisasContext *s, int opcode,
4173 int rd, int rn, int rm)
4174{
4175 TCGv_i32 tcg_op1;
4176 TCGv_i32 tcg_op2;
4177 TCGv_i32 tcg_res;
4178 TCGv_ptr fpst;
4179
4180 tcg_res = tcg_temp_new_i32();
4181 fpst = get_fpstatus_ptr();
4182 tcg_op1 = read_fp_sreg(s, rn);
4183 tcg_op2 = read_fp_sreg(s, rm);
4184
4185 switch (opcode) {
4186 case 0x0: /* FMUL */
4187 gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
4188 break;
4189 case 0x1: /* FDIV */
4190 gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst);
4191 break;
4192 case 0x2: /* FADD */
4193 gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
4194 break;
4195 case 0x3: /* FSUB */
4196 gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
4197 break;
4198 case 0x4: /* FMAX */
4199 gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
4200 break;
4201 case 0x5: /* FMIN */
4202 gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
4203 break;
4204 case 0x6: /* FMAXNM */
4205 gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
4206 break;
4207 case 0x7: /* FMINNM */
4208 gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
4209 break;
4210 case 0x8: /* FNMUL */
4211 gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
4212 gen_helper_vfp_negs(tcg_res, tcg_res);
4213 break;
4214 }
4215
4216 write_fp_sreg(s, rd, tcg_res);
4217
4218 tcg_temp_free_ptr(fpst);
4219 tcg_temp_free_i32(tcg_op1);
4220 tcg_temp_free_i32(tcg_op2);
4221 tcg_temp_free_i32(tcg_res);
4222}
4223
4224/* C3.6.26 Floating-point data-processing (2 source) - double precision */
4225static void handle_fp_2src_double(DisasContext *s, int opcode,
4226 int rd, int rn, int rm)
4227{
4228 TCGv_i64 tcg_op1;
4229 TCGv_i64 tcg_op2;
4230 TCGv_i64 tcg_res;
4231 TCGv_ptr fpst;
4232
4233 tcg_res = tcg_temp_new_i64();
4234 fpst = get_fpstatus_ptr();
4235 tcg_op1 = read_fp_dreg(s, rn);
4236 tcg_op2 = read_fp_dreg(s, rm);
4237
4238 switch (opcode) {
4239 case 0x0: /* FMUL */
4240 gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
4241 break;
4242 case 0x1: /* FDIV */
4243 gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst);
4244 break;
4245 case 0x2: /* FADD */
4246 gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
4247 break;
4248 case 0x3: /* FSUB */
4249 gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
4250 break;
4251 case 0x4: /* FMAX */
4252 gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
4253 break;
4254 case 0x5: /* FMIN */
4255 gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
4256 break;
4257 case 0x6: /* FMAXNM */
4258 gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
4259 break;
4260 case 0x7: /* FMINNM */
4261 gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
4262 break;
4263 case 0x8: /* FNMUL */
4264 gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
4265 gen_helper_vfp_negd(tcg_res, tcg_res);
4266 break;
4267 }
4268
4269 write_fp_dreg(s, rd, tcg_res);
4270
4271 tcg_temp_free_ptr(fpst);
4272 tcg_temp_free_i64(tcg_op1);
4273 tcg_temp_free_i64(tcg_op2);
4274 tcg_temp_free_i64(tcg_res);
4275}
4276
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004277/* C3.6.26 Floating point data-processing (2 source)
4278 * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
4279 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
4280 * | M | 0 | S | 1 1 1 1 0 | type | 1 | Rm | opcode | 1 0 | Rn | Rd |
4281 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
4282 */
4283static void disas_fp_2src(DisasContext *s, uint32_t insn)
4284{
Alexander Grafec73d2e2014-01-04 22:15:50 +00004285 int type = extract32(insn, 22, 2);
4286 int rd = extract32(insn, 0, 5);
4287 int rn = extract32(insn, 5, 5);
4288 int rm = extract32(insn, 16, 5);
4289 int opcode = extract32(insn, 12, 4);
4290
4291 if (opcode > 8) {
4292 unallocated_encoding(s);
4293 return;
4294 }
4295
4296 switch (type) {
4297 case 0:
4298 handle_fp_2src_single(s, opcode, rd, rn, rm);
4299 break;
4300 case 1:
4301 handle_fp_2src_double(s, opcode, rd, rn, rm);
4302 break;
4303 default:
4304 unallocated_encoding(s);
4305 }
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004306}
4307
Alexander Graf6a306672014-01-04 22:15:50 +00004308/* C3.6.27 Floating-point data-processing (3 source) - single precision */
4309static void handle_fp_3src_single(DisasContext *s, bool o0, bool o1,
4310 int rd, int rn, int rm, int ra)
4311{
4312 TCGv_i32 tcg_op1, tcg_op2, tcg_op3;
4313 TCGv_i32 tcg_res = tcg_temp_new_i32();
4314 TCGv_ptr fpst = get_fpstatus_ptr();
4315
4316 tcg_op1 = read_fp_sreg(s, rn);
4317 tcg_op2 = read_fp_sreg(s, rm);
4318 tcg_op3 = read_fp_sreg(s, ra);
4319
4320 /* These are fused multiply-add, and must be done as one
4321 * floating point operation with no rounding between the
4322 * multiplication and addition steps.
4323 * NB that doing the negations here as separate steps is
4324 * correct : an input NaN should come out with its sign bit
4325 * flipped if it is a negated-input.
4326 */
4327 if (o1 == true) {
4328 gen_helper_vfp_negs(tcg_op3, tcg_op3);
4329 }
4330
4331 if (o0 != o1) {
4332 gen_helper_vfp_negs(tcg_op1, tcg_op1);
4333 }
4334
4335 gen_helper_vfp_muladds(tcg_res, tcg_op1, tcg_op2, tcg_op3, fpst);
4336
4337 write_fp_sreg(s, rd, tcg_res);
4338
4339 tcg_temp_free_ptr(fpst);
4340 tcg_temp_free_i32(tcg_op1);
4341 tcg_temp_free_i32(tcg_op2);
4342 tcg_temp_free_i32(tcg_op3);
4343 tcg_temp_free_i32(tcg_res);
4344}
4345
4346/* C3.6.27 Floating-point data-processing (3 source) - double precision */
4347static void handle_fp_3src_double(DisasContext *s, bool o0, bool o1,
4348 int rd, int rn, int rm, int ra)
4349{
4350 TCGv_i64 tcg_op1, tcg_op2, tcg_op3;
4351 TCGv_i64 tcg_res = tcg_temp_new_i64();
4352 TCGv_ptr fpst = get_fpstatus_ptr();
4353
4354 tcg_op1 = read_fp_dreg(s, rn);
4355 tcg_op2 = read_fp_dreg(s, rm);
4356 tcg_op3 = read_fp_dreg(s, ra);
4357
4358 /* These are fused multiply-add, and must be done as one
4359 * floating point operation with no rounding between the
4360 * multiplication and addition steps.
4361 * NB that doing the negations here as separate steps is
4362 * correct : an input NaN should come out with its sign bit
4363 * flipped if it is a negated-input.
4364 */
4365 if (o1 == true) {
4366 gen_helper_vfp_negd(tcg_op3, tcg_op3);
4367 }
4368
4369 if (o0 != o1) {
4370 gen_helper_vfp_negd(tcg_op1, tcg_op1);
4371 }
4372
4373 gen_helper_vfp_muladdd(tcg_res, tcg_op1, tcg_op2, tcg_op3, fpst);
4374
4375 write_fp_dreg(s, rd, tcg_res);
4376
4377 tcg_temp_free_ptr(fpst);
4378 tcg_temp_free_i64(tcg_op1);
4379 tcg_temp_free_i64(tcg_op2);
4380 tcg_temp_free_i64(tcg_op3);
4381 tcg_temp_free_i64(tcg_res);
4382}
4383
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004384/* C3.6.27 Floating point data-processing (3 source)
4385 * 31 30 29 28 24 23 22 21 20 16 15 14 10 9 5 4 0
4386 * +---+---+---+-----------+------+----+------+----+------+------+------+
4387 * | M | 0 | S | 1 1 1 1 1 | type | o1 | Rm | o0 | Ra | Rn | Rd |
4388 * +---+---+---+-----------+------+----+------+----+------+------+------+
4389 */
4390static void disas_fp_3src(DisasContext *s, uint32_t insn)
4391{
Alexander Graf6a306672014-01-04 22:15:50 +00004392 int type = extract32(insn, 22, 2);
4393 int rd = extract32(insn, 0, 5);
4394 int rn = extract32(insn, 5, 5);
4395 int ra = extract32(insn, 10, 5);
4396 int rm = extract32(insn, 16, 5);
4397 bool o0 = extract32(insn, 15, 1);
4398 bool o1 = extract32(insn, 21, 1);
4399
4400 switch (type) {
4401 case 0:
4402 handle_fp_3src_single(s, o0, o1, rd, rn, rm, ra);
4403 break;
4404 case 1:
4405 handle_fp_3src_double(s, o0, o1, rd, rn, rm, ra);
4406 break;
4407 default:
4408 unallocated_encoding(s);
4409 }
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004410}
4411
4412/* C3.6.28 Floating point immediate
4413 * 31 30 29 28 24 23 22 21 20 13 12 10 9 5 4 0
4414 * +---+---+---+-----------+------+---+------------+-------+------+------+
4415 * | M | 0 | S | 1 1 1 1 0 | type | 1 | imm8 | 1 0 0 | imm5 | Rd |
4416 * +---+---+---+-----------+------+---+------------+-------+------+------+
4417 */
4418static void disas_fp_imm(DisasContext *s, uint32_t insn)
4419{
Alexander Graf6163f862014-01-04 22:15:50 +00004420 int rd = extract32(insn, 0, 5);
4421 int imm8 = extract32(insn, 13, 8);
4422 int is_double = extract32(insn, 22, 2);
4423 uint64_t imm;
4424 TCGv_i64 tcg_res;
4425
4426 if (is_double > 1) {
4427 unallocated_encoding(s);
4428 return;
4429 }
4430
4431 /* The imm8 encodes the sign bit, enough bits to represent
4432 * an exponent in the range 01....1xx to 10....0xx,
4433 * and the most significant 4 bits of the mantissa; see
4434 * VFPExpandImm() in the v8 ARM ARM.
4435 */
4436 if (is_double) {
4437 imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
4438 (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) |
4439 extract32(imm8, 0, 6);
4440 imm <<= 48;
4441 } else {
4442 imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
4443 (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) |
4444 (extract32(imm8, 0, 6) << 3);
4445 imm <<= 16;
4446 }
4447
4448 tcg_res = tcg_const_i64(imm);
4449 write_fp_dreg(s, rd, tcg_res);
4450 tcg_temp_free_i64(tcg_res);
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004451}
4452
Alexander Graf52a1f6a2014-01-07 17:19:14 +00004453/* Handle floating point <=> fixed point conversions. Note that we can
4454 * also deal with fp <=> integer conversions as a special case (scale == 64)
4455 * OPTME: consider handling that special case specially or at least skipping
4456 * the call to scalbn in the helpers for zero shifts.
4457 */
4458static void handle_fpfpcvt(DisasContext *s, int rd, int rn, int opcode,
4459 bool itof, int rmode, int scale, int sf, int type)
4460{
4461 bool is_signed = !(opcode & 1);
4462 bool is_double = type;
4463 TCGv_ptr tcg_fpstatus;
4464 TCGv_i32 tcg_shift;
4465
4466 tcg_fpstatus = get_fpstatus_ptr();
4467
4468 tcg_shift = tcg_const_i32(64 - scale);
4469
4470 if (itof) {
4471 TCGv_i64 tcg_int = cpu_reg(s, rn);
4472 if (!sf) {
4473 TCGv_i64 tcg_extend = new_tmp_a64(s);
4474
4475 if (is_signed) {
4476 tcg_gen_ext32s_i64(tcg_extend, tcg_int);
4477 } else {
4478 tcg_gen_ext32u_i64(tcg_extend, tcg_int);
4479 }
4480
4481 tcg_int = tcg_extend;
4482 }
4483
4484 if (is_double) {
4485 TCGv_i64 tcg_double = tcg_temp_new_i64();
4486 if (is_signed) {
4487 gen_helper_vfp_sqtod(tcg_double, tcg_int,
4488 tcg_shift, tcg_fpstatus);
4489 } else {
4490 gen_helper_vfp_uqtod(tcg_double, tcg_int,
4491 tcg_shift, tcg_fpstatus);
4492 }
4493 write_fp_dreg(s, rd, tcg_double);
4494 tcg_temp_free_i64(tcg_double);
4495 } else {
4496 TCGv_i32 tcg_single = tcg_temp_new_i32();
4497 if (is_signed) {
4498 gen_helper_vfp_sqtos(tcg_single, tcg_int,
4499 tcg_shift, tcg_fpstatus);
4500 } else {
4501 gen_helper_vfp_uqtos(tcg_single, tcg_int,
4502 tcg_shift, tcg_fpstatus);
4503 }
4504 write_fp_sreg(s, rd, tcg_single);
4505 tcg_temp_free_i32(tcg_single);
4506 }
4507 } else {
4508 TCGv_i64 tcg_int = cpu_reg(s, rd);
4509 TCGv_i32 tcg_rmode;
4510
4511 if (extract32(opcode, 2, 1)) {
4512 /* There are too many rounding modes to all fit into rmode,
4513 * so FCVTA[US] is a special case.
4514 */
4515 rmode = FPROUNDING_TIEAWAY;
4516 }
4517
4518 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
4519
4520 gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
4521
4522 if (is_double) {
4523 TCGv_i64 tcg_double = read_fp_dreg(s, rn);
4524 if (is_signed) {
4525 if (!sf) {
4526 gen_helper_vfp_tosld(tcg_int, tcg_double,
4527 tcg_shift, tcg_fpstatus);
4528 } else {
4529 gen_helper_vfp_tosqd(tcg_int, tcg_double,
4530 tcg_shift, tcg_fpstatus);
4531 }
4532 } else {
4533 if (!sf) {
4534 gen_helper_vfp_tould(tcg_int, tcg_double,
4535 tcg_shift, tcg_fpstatus);
4536 } else {
4537 gen_helper_vfp_touqd(tcg_int, tcg_double,
4538 tcg_shift, tcg_fpstatus);
4539 }
4540 }
4541 tcg_temp_free_i64(tcg_double);
4542 } else {
4543 TCGv_i32 tcg_single = read_fp_sreg(s, rn);
4544 if (sf) {
4545 if (is_signed) {
4546 gen_helper_vfp_tosqs(tcg_int, tcg_single,
4547 tcg_shift, tcg_fpstatus);
4548 } else {
4549 gen_helper_vfp_touqs(tcg_int, tcg_single,
4550 tcg_shift, tcg_fpstatus);
4551 }
4552 } else {
4553 TCGv_i32 tcg_dest = tcg_temp_new_i32();
4554 if (is_signed) {
4555 gen_helper_vfp_tosls(tcg_dest, tcg_single,
4556 tcg_shift, tcg_fpstatus);
4557 } else {
4558 gen_helper_vfp_touls(tcg_dest, tcg_single,
4559 tcg_shift, tcg_fpstatus);
4560 }
4561 tcg_gen_extu_i32_i64(tcg_int, tcg_dest);
4562 tcg_temp_free_i32(tcg_dest);
4563 }
4564 tcg_temp_free_i32(tcg_single);
4565 }
4566
4567 gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
4568 tcg_temp_free_i32(tcg_rmode);
4569
4570 if (!sf) {
4571 tcg_gen_ext32u_i64(tcg_int, tcg_int);
4572 }
4573 }
4574
4575 tcg_temp_free_ptr(tcg_fpstatus);
4576 tcg_temp_free_i32(tcg_shift);
4577}
4578
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004579/* C3.6.29 Floating point <-> fixed point conversions
4580 * 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0
4581 * +----+---+---+-----------+------+---+-------+--------+-------+------+------+
4582 * | sf | 0 | S | 1 1 1 1 0 | type | 0 | rmode | opcode | scale | Rn | Rd |
4583 * +----+---+---+-----------+------+---+-------+--------+-------+------+------+
4584 */
4585static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn)
4586{
Alexander Graf52a1f6a2014-01-07 17:19:14 +00004587 int rd = extract32(insn, 0, 5);
4588 int rn = extract32(insn, 5, 5);
4589 int scale = extract32(insn, 10, 6);
4590 int opcode = extract32(insn, 16, 3);
4591 int rmode = extract32(insn, 19, 2);
4592 int type = extract32(insn, 22, 2);
4593 bool sbit = extract32(insn, 29, 1);
4594 bool sf = extract32(insn, 31, 1);
4595 bool itof;
4596
4597 if (sbit || (type > 1)
4598 || (!sf && scale < 32)) {
4599 unallocated_encoding(s);
4600 return;
4601 }
4602
4603 switch ((rmode << 3) | opcode) {
4604 case 0x2: /* SCVTF */
4605 case 0x3: /* UCVTF */
4606 itof = true;
4607 break;
4608 case 0x18: /* FCVTZS */
4609 case 0x19: /* FCVTZU */
4610 itof = false;
4611 break;
4612 default:
4613 unallocated_encoding(s);
4614 return;
4615 }
4616
4617 handle_fpfpcvt(s, rd, rn, opcode, itof, FPROUNDING_ZERO, scale, sf, type);
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004618}
4619
Peter Maydellce5458e2013-12-23 23:27:31 +00004620static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
4621{
4622 /* FMOV: gpr to or from float, double, or top half of quad fp reg,
4623 * without conversion.
4624 */
4625
4626 if (itof) {
Peter Maydellce5458e2013-12-23 23:27:31 +00004627 TCGv_i64 tcg_rn = cpu_reg(s, rn);
4628
4629 switch (type) {
4630 case 0:
4631 {
4632 /* 32 bit */
4633 TCGv_i64 tmp = tcg_temp_new_i64();
4634 tcg_gen_ext32u_i64(tmp, tcg_rn);
Peter Maydelle2f90562014-01-04 22:15:49 +00004635 tcg_gen_st_i64(tmp, cpu_env, fp_reg_offset(rd, MO_64));
Peter Maydellce5458e2013-12-23 23:27:31 +00004636 tcg_gen_movi_i64(tmp, 0);
Peter Maydelle2f90562014-01-04 22:15:49 +00004637 tcg_gen_st_i64(tmp, cpu_env, fp_reg_hi_offset(rd));
Peter Maydellce5458e2013-12-23 23:27:31 +00004638 tcg_temp_free_i64(tmp);
4639 break;
4640 }
4641 case 1:
4642 {
4643 /* 64 bit */
4644 TCGv_i64 tmp = tcg_const_i64(0);
Peter Maydelle2f90562014-01-04 22:15:49 +00004645 tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_offset(rd, MO_64));
4646 tcg_gen_st_i64(tmp, cpu_env, fp_reg_hi_offset(rd));
Peter Maydellce5458e2013-12-23 23:27:31 +00004647 tcg_temp_free_i64(tmp);
4648 break;
4649 }
4650 case 2:
4651 /* 64 bit to top half. */
Peter Maydelle2f90562014-01-04 22:15:49 +00004652 tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_hi_offset(rd));
Peter Maydellce5458e2013-12-23 23:27:31 +00004653 break;
4654 }
4655 } else {
Peter Maydellce5458e2013-12-23 23:27:31 +00004656 TCGv_i64 tcg_rd = cpu_reg(s, rd);
4657
4658 switch (type) {
4659 case 0:
4660 /* 32 bit */
Peter Maydelle2f90562014-01-04 22:15:49 +00004661 tcg_gen_ld32u_i64(tcg_rd, cpu_env, fp_reg_offset(rn, MO_32));
4662 break;
4663 case 1:
4664 /* 64 bit */
4665 tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_offset(rn, MO_64));
Peter Maydellce5458e2013-12-23 23:27:31 +00004666 break;
4667 case 2:
4668 /* 64 bits from top half */
Peter Maydelle2f90562014-01-04 22:15:49 +00004669 tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_hi_offset(rn));
Peter Maydellce5458e2013-12-23 23:27:31 +00004670 break;
4671 }
4672 }
4673}
4674
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004675/* C3.6.30 Floating point <-> integer conversions
4676 * 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0
4677 * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
Will Newtonc436d402014-01-07 17:19:14 +00004678 * | sf | 0 | S | 1 1 1 1 0 | type | 1 | rmode | opc | 0 0 0 0 0 0 | Rn | Rd |
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004679 * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
4680 */
4681static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
4682{
Peter Maydellce5458e2013-12-23 23:27:31 +00004683 int rd = extract32(insn, 0, 5);
4684 int rn = extract32(insn, 5, 5);
4685 int opcode = extract32(insn, 16, 3);
4686 int rmode = extract32(insn, 19, 2);
4687 int type = extract32(insn, 22, 2);
4688 bool sbit = extract32(insn, 29, 1);
4689 bool sf = extract32(insn, 31, 1);
4690
Will Newtonc436d402014-01-07 17:19:14 +00004691 if (sbit) {
4692 unallocated_encoding(s);
4693 return;
4694 }
4695
4696 if (opcode > 5) {
Peter Maydellce5458e2013-12-23 23:27:31 +00004697 /* FMOV */
4698 bool itof = opcode & 1;
4699
Will Newtonc436d402014-01-07 17:19:14 +00004700 if (rmode >= 2) {
4701 unallocated_encoding(s);
4702 return;
4703 }
4704
Peter Maydellce5458e2013-12-23 23:27:31 +00004705 switch (sf << 3 | type << 1 | rmode) {
4706 case 0x0: /* 32 bit */
4707 case 0xa: /* 64 bit */
4708 case 0xd: /* 64 bit to top half of quad */
4709 break;
4710 default:
4711 /* all other sf/type/rmode combinations are invalid */
4712 unallocated_encoding(s);
4713 break;
4714 }
4715
4716 handle_fmov(s, rd, rn, type, itof);
4717 } else {
4718 /* actual FP conversions */
Will Newtonc436d402014-01-07 17:19:14 +00004719 bool itof = extract32(opcode, 1, 1);
4720
4721 if (type > 1 || (rmode != 0 && opcode > 1)) {
4722 unallocated_encoding(s);
4723 return;
4724 }
4725
4726 handle_fpfpcvt(s, rd, rn, opcode, itof, rmode, 64, sf, type);
Peter Maydellce5458e2013-12-23 23:27:31 +00004727 }
Peter Maydellfaa0ba42013-12-23 23:27:30 +00004728}
4729
4730/* FP-specific subcases of table C3-6 (SIMD and FP data processing)
4731 * 31 30 29 28 25 24 0
4732 * +---+---+---+---------+-----------------------------+
4733 * | | 0 | | 1 1 1 1 | |
4734 * +---+---+---+---------+-----------------------------+
4735 */
4736static void disas_data_proc_fp(DisasContext *s, uint32_t insn)
4737{
4738 if (extract32(insn, 24, 1)) {
4739 /* Floating point data-processing (3 source) */
4740 disas_fp_3src(s, insn);
4741 } else if (extract32(insn, 21, 1) == 0) {
4742 /* Floating point to fixed point conversions */
4743 disas_fp_fixed_conv(s, insn);
4744 } else {
4745 switch (extract32(insn, 10, 2)) {
4746 case 1:
4747 /* Floating point conditional compare */
4748 disas_fp_ccomp(s, insn);
4749 break;
4750 case 2:
4751 /* Floating point data-processing (2 source) */
4752 disas_fp_2src(s, insn);
4753 break;
4754 case 3:
4755 /* Floating point conditional select */
4756 disas_fp_csel(s, insn);
4757 break;
4758 case 0:
4759 switch (ctz32(extract32(insn, 12, 4))) {
4760 case 0: /* [15:12] == xxx1 */
4761 /* Floating point immediate */
4762 disas_fp_imm(s, insn);
4763 break;
4764 case 1: /* [15:12] == xx10 */
4765 /* Floating point compare */
4766 disas_fp_compare(s, insn);
4767 break;
4768 case 2: /* [15:12] == x100 */
4769 /* Floating point data-processing (1 source) */
4770 disas_fp_1src(s, insn);
4771 break;
4772 case 3: /* [15:12] == 1000 */
4773 unallocated_encoding(s);
4774 break;
4775 default: /* [15:12] == 0000 */
4776 /* Floating point <-> integer conversions */
4777 disas_fp_int_conv(s, insn);
4778 break;
4779 }
4780 break;
4781 }
4782 }
4783}
4784
Peter Maydell5c737472014-01-31 14:47:30 +00004785static void do_ext64(DisasContext *s, TCGv_i64 tcg_left, TCGv_i64 tcg_right,
4786 int pos)
4787{
4788 /* Extract 64 bits from the middle of two concatenated 64 bit
4789 * vector register slices left:right. The extracted bits start
4790 * at 'pos' bits into the right (least significant) side.
4791 * We return the result in tcg_right, and guarantee not to
4792 * trash tcg_left.
4793 */
4794 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
4795 assert(pos > 0 && pos < 64);
4796
4797 tcg_gen_shri_i64(tcg_right, tcg_right, pos);
4798 tcg_gen_shli_i64(tcg_tmp, tcg_left, 64 - pos);
4799 tcg_gen_or_i64(tcg_right, tcg_right, tcg_tmp);
4800
4801 tcg_temp_free_i64(tcg_tmp);
4802}
4803
Alex Bennée384b26f2014-01-31 14:47:30 +00004804/* C3.6.1 EXT
4805 * 31 30 29 24 23 22 21 20 16 15 14 11 10 9 5 4 0
4806 * +---+---+-------------+-----+---+------+---+------+---+------+------+
4807 * | 0 | Q | 1 0 1 1 1 0 | op2 | 0 | Rm | 0 | imm4 | 0 | Rn | Rd |
4808 * +---+---+-------------+-----+---+------+---+------+---+------+------+
4809 */
4810static void disas_simd_ext(DisasContext *s, uint32_t insn)
4811{
Peter Maydell5c737472014-01-31 14:47:30 +00004812 int is_q = extract32(insn, 30, 1);
4813 int op2 = extract32(insn, 22, 2);
4814 int imm4 = extract32(insn, 11, 4);
4815 int rm = extract32(insn, 16, 5);
4816 int rn = extract32(insn, 5, 5);
4817 int rd = extract32(insn, 0, 5);
4818 int pos = imm4 << 3;
4819 TCGv_i64 tcg_resl, tcg_resh;
4820
4821 if (op2 != 0 || (!is_q && extract32(imm4, 3, 1))) {
4822 unallocated_encoding(s);
4823 return;
4824 }
4825
4826 tcg_resh = tcg_temp_new_i64();
4827 tcg_resl = tcg_temp_new_i64();
4828
4829 /* Vd gets bits starting at pos bits into Vm:Vn. This is
4830 * either extracting 128 bits from a 128:128 concatenation, or
4831 * extracting 64 bits from a 64:64 concatenation.
4832 */
4833 if (!is_q) {
4834 read_vec_element(s, tcg_resl, rn, 0, MO_64);
4835 if (pos != 0) {
4836 read_vec_element(s, tcg_resh, rm, 0, MO_64);
4837 do_ext64(s, tcg_resh, tcg_resl, pos);
4838 }
4839 tcg_gen_movi_i64(tcg_resh, 0);
4840 } else {
4841 TCGv_i64 tcg_hh;
4842 typedef struct {
4843 int reg;
4844 int elt;
4845 } EltPosns;
4846 EltPosns eltposns[] = { {rn, 0}, {rn, 1}, {rm, 0}, {rm, 1} };
4847 EltPosns *elt = eltposns;
4848
4849 if (pos >= 64) {
4850 elt++;
4851 pos -= 64;
4852 }
4853
4854 read_vec_element(s, tcg_resl, elt->reg, elt->elt, MO_64);
4855 elt++;
4856 read_vec_element(s, tcg_resh, elt->reg, elt->elt, MO_64);
4857 elt++;
4858 if (pos != 0) {
4859 do_ext64(s, tcg_resh, tcg_resl, pos);
4860 tcg_hh = tcg_temp_new_i64();
4861 read_vec_element(s, tcg_hh, elt->reg, elt->elt, MO_64);
4862 do_ext64(s, tcg_hh, tcg_resh, pos);
4863 tcg_temp_free_i64(tcg_hh);
4864 }
4865 }
4866
4867 write_vec_element(s, tcg_resl, rd, 0, MO_64);
4868 tcg_temp_free_i64(tcg_resl);
4869 write_vec_element(s, tcg_resh, rd, 1, MO_64);
4870 tcg_temp_free_i64(tcg_resh);
Alex Bennée384b26f2014-01-31 14:47:30 +00004871}
4872
4873/* C3.6.2 TBL/TBX
4874 * 31 30 29 24 23 22 21 20 16 15 14 13 12 11 10 9 5 4 0
4875 * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+
4876 * | 0 | Q | 0 0 1 1 1 0 | op2 | 0 | Rm | 0 | len | op | 0 0 | Rn | Rd |
4877 * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+
4878 */
4879static void disas_simd_tb(DisasContext *s, uint32_t insn)
4880{
Michael Matz7c510482014-01-31 14:47:31 +00004881 int op2 = extract32(insn, 22, 2);
4882 int is_q = extract32(insn, 30, 1);
4883 int rm = extract32(insn, 16, 5);
4884 int rn = extract32(insn, 5, 5);
4885 int rd = extract32(insn, 0, 5);
4886 int is_tblx = extract32(insn, 12, 1);
4887 int len = extract32(insn, 13, 2);
4888 TCGv_i64 tcg_resl, tcg_resh, tcg_idx;
4889 TCGv_i32 tcg_regno, tcg_numregs;
4890
4891 if (op2 != 0) {
4892 unallocated_encoding(s);
4893 return;
4894 }
4895
4896 /* This does a table lookup: for every byte element in the input
4897 * we index into a table formed from up to four vector registers,
4898 * and then the output is the result of the lookups. Our helper
4899 * function does the lookup operation for a single 64 bit part of
4900 * the input.
4901 */
4902 tcg_resl = tcg_temp_new_i64();
4903 tcg_resh = tcg_temp_new_i64();
4904
4905 if (is_tblx) {
4906 read_vec_element(s, tcg_resl, rd, 0, MO_64);
4907 } else {
4908 tcg_gen_movi_i64(tcg_resl, 0);
4909 }
4910 if (is_tblx && is_q) {
4911 read_vec_element(s, tcg_resh, rd, 1, MO_64);
4912 } else {
4913 tcg_gen_movi_i64(tcg_resh, 0);
4914 }
4915
4916 tcg_idx = tcg_temp_new_i64();
4917 tcg_regno = tcg_const_i32(rn);
4918 tcg_numregs = tcg_const_i32(len + 1);
4919 read_vec_element(s, tcg_idx, rm, 0, MO_64);
4920 gen_helper_simd_tbl(tcg_resl, cpu_env, tcg_resl, tcg_idx,
4921 tcg_regno, tcg_numregs);
4922 if (is_q) {
4923 read_vec_element(s, tcg_idx, rm, 1, MO_64);
4924 gen_helper_simd_tbl(tcg_resh, cpu_env, tcg_resh, tcg_idx,
4925 tcg_regno, tcg_numregs);
4926 }
4927 tcg_temp_free_i64(tcg_idx);
4928 tcg_temp_free_i32(tcg_regno);
4929 tcg_temp_free_i32(tcg_numregs);
4930
4931 write_vec_element(s, tcg_resl, rd, 0, MO_64);
4932 tcg_temp_free_i64(tcg_resl);
4933 write_vec_element(s, tcg_resh, rd, 1, MO_64);
4934 tcg_temp_free_i64(tcg_resh);
Alex Bennée384b26f2014-01-31 14:47:30 +00004935}
4936
4937/* C3.6.3 ZIP/UZP/TRN
4938 * 31 30 29 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0
4939 * +---+---+-------------+------+---+------+---+------------------+------+
4940 * | 0 | Q | 0 0 1 1 1 0 | size | 0 | Rm | 0 | opc | 1 0 | Rn | Rd |
4941 * +---+---+-------------+------+---+------+---+------------------+------+
4942 */
4943static void disas_simd_zip_trn(DisasContext *s, uint32_t insn)
4944{
Michael Matz5fa54692014-01-31 14:47:31 +00004945 int rd = extract32(insn, 0, 5);
4946 int rn = extract32(insn, 5, 5);
4947 int rm = extract32(insn, 16, 5);
4948 int size = extract32(insn, 22, 2);
4949 /* opc field bits [1:0] indicate ZIP/UZP/TRN;
4950 * bit 2 indicates 1 vs 2 variant of the insn.
4951 */
4952 int opcode = extract32(insn, 12, 2);
4953 bool part = extract32(insn, 14, 1);
4954 bool is_q = extract32(insn, 30, 1);
4955 int esize = 8 << size;
4956 int i, ofs;
4957 int datasize = is_q ? 128 : 64;
4958 int elements = datasize / esize;
4959 TCGv_i64 tcg_res, tcg_resl, tcg_resh;
4960
4961 if (opcode == 0 || (size == 3 && !is_q)) {
4962 unallocated_encoding(s);
4963 return;
4964 }
4965
4966 tcg_resl = tcg_const_i64(0);
4967 tcg_resh = tcg_const_i64(0);
4968 tcg_res = tcg_temp_new_i64();
4969
4970 for (i = 0; i < elements; i++) {
4971 switch (opcode) {
4972 case 1: /* UZP1/2 */
4973 {
4974 int midpoint = elements / 2;
4975 if (i < midpoint) {
4976 read_vec_element(s, tcg_res, rn, 2 * i + part, size);
4977 } else {
4978 read_vec_element(s, tcg_res, rm,
4979 2 * (i - midpoint) + part, size);
4980 }
4981 break;
4982 }
4983 case 2: /* TRN1/2 */
4984 if (i & 1) {
4985 read_vec_element(s, tcg_res, rm, (i & ~1) + part, size);
4986 } else {
4987 read_vec_element(s, tcg_res, rn, (i & ~1) + part, size);
4988 }
4989 break;
4990 case 3: /* ZIP1/2 */
4991 {
4992 int base = part * elements / 2;
4993 if (i & 1) {
4994 read_vec_element(s, tcg_res, rm, base + (i >> 1), size);
4995 } else {
4996 read_vec_element(s, tcg_res, rn, base + (i >> 1), size);
4997 }
4998 break;
4999 }
5000 default:
5001 g_assert_not_reached();
5002 }
5003
5004 ofs = i * esize;
5005 if (ofs < 64) {
5006 tcg_gen_shli_i64(tcg_res, tcg_res, ofs);
5007 tcg_gen_or_i64(tcg_resl, tcg_resl, tcg_res);
5008 } else {
5009 tcg_gen_shli_i64(tcg_res, tcg_res, ofs - 64);
5010 tcg_gen_or_i64(tcg_resh, tcg_resh, tcg_res);
5011 }
5012 }
5013
5014 tcg_temp_free_i64(tcg_res);
5015
5016 write_vec_element(s, tcg_resl, rd, 0, MO_64);
5017 tcg_temp_free_i64(tcg_resl);
5018 write_vec_element(s, tcg_resh, rd, 1, MO_64);
5019 tcg_temp_free_i64(tcg_resh);
Alex Bennée384b26f2014-01-31 14:47:30 +00005020}
5021
Michael Matz4a0ff1c2014-01-31 14:47:31 +00005022static void do_minmaxop(DisasContext *s, TCGv_i32 tcg_elt1, TCGv_i32 tcg_elt2,
5023 int opc, bool is_min, TCGv_ptr fpst)
5024{
5025 /* Helper function for disas_simd_across_lanes: do a single precision
5026 * min/max operation on the specified two inputs,
5027 * and return the result in tcg_elt1.
5028 */
5029 if (opc == 0xc) {
5030 if (is_min) {
5031 gen_helper_vfp_minnums(tcg_elt1, tcg_elt1, tcg_elt2, fpst);
5032 } else {
5033 gen_helper_vfp_maxnums(tcg_elt1, tcg_elt1, tcg_elt2, fpst);
5034 }
5035 } else {
5036 assert(opc == 0xf);
5037 if (is_min) {
5038 gen_helper_vfp_mins(tcg_elt1, tcg_elt1, tcg_elt2, fpst);
5039 } else {
5040 gen_helper_vfp_maxs(tcg_elt1, tcg_elt1, tcg_elt2, fpst);
5041 }
5042 }
5043}
5044
Alex Bennée384b26f2014-01-31 14:47:30 +00005045/* C3.6.4 AdvSIMD across lanes
5046 * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
5047 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
5048 * | 0 | Q | U | 0 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 | Rn | Rd |
5049 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
5050 */
5051static void disas_simd_across_lanes(DisasContext *s, uint32_t insn)
5052{
Michael Matz4a0ff1c2014-01-31 14:47:31 +00005053 int rd = extract32(insn, 0, 5);
5054 int rn = extract32(insn, 5, 5);
5055 int size = extract32(insn, 22, 2);
5056 int opcode = extract32(insn, 12, 5);
5057 bool is_q = extract32(insn, 30, 1);
5058 bool is_u = extract32(insn, 29, 1);
5059 bool is_fp = false;
5060 bool is_min = false;
5061 int esize;
5062 int elements;
5063 int i;
5064 TCGv_i64 tcg_res, tcg_elt;
5065
5066 switch (opcode) {
5067 case 0x1b: /* ADDV */
5068 if (is_u) {
5069 unallocated_encoding(s);
5070 return;
5071 }
5072 /* fall through */
5073 case 0x3: /* SADDLV, UADDLV */
5074 case 0xa: /* SMAXV, UMAXV */
5075 case 0x1a: /* SMINV, UMINV */
5076 if (size == 3 || (size == 2 && !is_q)) {
5077 unallocated_encoding(s);
5078 return;
5079 }
5080 break;
5081 case 0xc: /* FMAXNMV, FMINNMV */
5082 case 0xf: /* FMAXV, FMINV */
5083 if (!is_u || !is_q || extract32(size, 0, 1)) {
5084 unallocated_encoding(s);
5085 return;
5086 }
5087 /* Bit 1 of size field encodes min vs max, and actual size is always
5088 * 32 bits: adjust the size variable so following code can rely on it
5089 */
5090 is_min = extract32(size, 1, 1);
5091 is_fp = true;
5092 size = 2;
5093 break;
5094 default:
5095 unallocated_encoding(s);
5096 return;
5097 }
5098
5099 esize = 8 << size;
5100 elements = (is_q ? 128 : 64) / esize;
5101
5102 tcg_res = tcg_temp_new_i64();
5103 tcg_elt = tcg_temp_new_i64();
5104
5105 /* These instructions operate across all lanes of a vector
5106 * to produce a single result. We can guarantee that a 64
5107 * bit intermediate is sufficient:
5108 * + for [US]ADDLV the maximum element size is 32 bits, and
5109 * the result type is 64 bits
5110 * + for FMAX*V, FMIN*V, ADDV the intermediate type is the
5111 * same as the element size, which is 32 bits at most
5112 * For the integer operations we can choose to work at 64
5113 * or 32 bits and truncate at the end; for simplicity
5114 * we use 64 bits always. The floating point
5115 * ops do require 32 bit intermediates, though.
5116 */
5117 if (!is_fp) {
5118 read_vec_element(s, tcg_res, rn, 0, size | (is_u ? 0 : MO_SIGN));
5119
5120 for (i = 1; i < elements; i++) {
5121 read_vec_element(s, tcg_elt, rn, i, size | (is_u ? 0 : MO_SIGN));
5122
5123 switch (opcode) {
5124 case 0x03: /* SADDLV / UADDLV */
5125 case 0x1b: /* ADDV */
5126 tcg_gen_add_i64(tcg_res, tcg_res, tcg_elt);
5127 break;
5128 case 0x0a: /* SMAXV / UMAXV */
5129 tcg_gen_movcond_i64(is_u ? TCG_COND_GEU : TCG_COND_GE,
5130 tcg_res,
5131 tcg_res, tcg_elt, tcg_res, tcg_elt);
5132 break;
5133 case 0x1a: /* SMINV / UMINV */
5134 tcg_gen_movcond_i64(is_u ? TCG_COND_LEU : TCG_COND_LE,
5135 tcg_res,
5136 tcg_res, tcg_elt, tcg_res, tcg_elt);
5137 break;
5138 break;
5139 default:
5140 g_assert_not_reached();
5141 }
5142
5143 }
5144 } else {
5145 /* Floating point ops which work on 32 bit (single) intermediates.
5146 * Note that correct NaN propagation requires that we do these
5147 * operations in exactly the order specified by the pseudocode.
5148 */
5149 TCGv_i32 tcg_elt1 = tcg_temp_new_i32();
5150 TCGv_i32 tcg_elt2 = tcg_temp_new_i32();
5151 TCGv_i32 tcg_elt3 = tcg_temp_new_i32();
5152 TCGv_ptr fpst = get_fpstatus_ptr();
5153
5154 assert(esize == 32);
5155 assert(elements == 4);
5156
5157 read_vec_element(s, tcg_elt, rn, 0, MO_32);
5158 tcg_gen_trunc_i64_i32(tcg_elt1, tcg_elt);
5159 read_vec_element(s, tcg_elt, rn, 1, MO_32);
5160 tcg_gen_trunc_i64_i32(tcg_elt2, tcg_elt);
5161
5162 do_minmaxop(s, tcg_elt1, tcg_elt2, opcode, is_min, fpst);
5163
5164 read_vec_element(s, tcg_elt, rn, 2, MO_32);
5165 tcg_gen_trunc_i64_i32(tcg_elt2, tcg_elt);
5166 read_vec_element(s, tcg_elt, rn, 3, MO_32);
5167 tcg_gen_trunc_i64_i32(tcg_elt3, tcg_elt);
5168
5169 do_minmaxop(s, tcg_elt2, tcg_elt3, opcode, is_min, fpst);
5170
5171 do_minmaxop(s, tcg_elt1, tcg_elt2, opcode, is_min, fpst);
5172
5173 tcg_gen_extu_i32_i64(tcg_res, tcg_elt1);
5174 tcg_temp_free_i32(tcg_elt1);
5175 tcg_temp_free_i32(tcg_elt2);
5176 tcg_temp_free_i32(tcg_elt3);
5177 tcg_temp_free_ptr(fpst);
5178 }
5179
5180 tcg_temp_free_i64(tcg_elt);
5181
5182 /* Now truncate the result to the width required for the final output */
5183 if (opcode == 0x03) {
5184 /* SADDLV, UADDLV: result is 2*esize */
5185 size++;
5186 }
5187
5188 switch (size) {
5189 case 0:
5190 tcg_gen_ext8u_i64(tcg_res, tcg_res);
5191 break;
5192 case 1:
5193 tcg_gen_ext16u_i64(tcg_res, tcg_res);
5194 break;
5195 case 2:
5196 tcg_gen_ext32u_i64(tcg_res, tcg_res);
5197 break;
5198 case 3:
5199 break;
5200 default:
5201 g_assert_not_reached();
5202 }
5203
5204 write_fp_dreg(s, rd, tcg_res);
5205 tcg_temp_free_i64(tcg_res);
Alex Bennée384b26f2014-01-31 14:47:30 +00005206}
5207
Alex Bennée67bb9382014-01-31 14:47:31 +00005208/* C6.3.31 DUP (Element, Vector)
5209 *
5210 * 31 30 29 21 20 16 15 10 9 5 4 0
5211 * +---+---+-------------------+--------+-------------+------+------+
5212 * | 0 | Q | 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 0 0 0 1 | Rn | Rd |
5213 * +---+---+-------------------+--------+-------------+------+------+
5214 *
5215 * size: encoded in imm5 (see ARM ARM LowestSetBit())
5216 */
5217static void handle_simd_dupe(DisasContext *s, int is_q, int rd, int rn,
5218 int imm5)
5219{
5220 int size = ctz32(imm5);
5221 int esize = 8 << size;
5222 int elements = (is_q ? 128 : 64) / esize;
5223 int index, i;
5224 TCGv_i64 tmp;
5225
5226 if (size > 3 || (size == 3 && !is_q)) {
5227 unallocated_encoding(s);
5228 return;
5229 }
5230
5231 index = imm5 >> (size + 1);
5232
5233 tmp = tcg_temp_new_i64();
5234 read_vec_element(s, tmp, rn, index, size);
5235
5236 for (i = 0; i < elements; i++) {
5237 write_vec_element(s, tmp, rd, i, size);
5238 }
5239
5240 if (!is_q) {
5241 clear_vec_high(s, rd);
5242 }
5243
5244 tcg_temp_free_i64(tmp);
5245}
5246
Peter Maydell360a6f22014-01-31 14:47:32 +00005247/* C6.3.31 DUP (element, scalar)
5248 * 31 21 20 16 15 10 9 5 4 0
5249 * +-----------------------+--------+-------------+------+------+
5250 * | 0 1 0 1 1 1 1 0 0 0 0 | imm5 | 0 0 0 0 0 1 | Rn | Rd |
5251 * +-----------------------+--------+-------------+------+------+
5252 */
5253static void handle_simd_dupes(DisasContext *s, int rd, int rn,
5254 int imm5)
5255{
5256 int size = ctz32(imm5);
5257 int index;
5258 TCGv_i64 tmp;
5259
5260 if (size > 3) {
5261 unallocated_encoding(s);
5262 return;
5263 }
5264
5265 index = imm5 >> (size + 1);
5266
5267 /* This instruction just extracts the specified element and
5268 * zero-extends it into the bottom of the destination register.
5269 */
5270 tmp = tcg_temp_new_i64();
5271 read_vec_element(s, tmp, rn, index, size);
5272 write_fp_dreg(s, rd, tmp);
5273 tcg_temp_free_i64(tmp);
5274}
5275
Alex Bennée67bb9382014-01-31 14:47:31 +00005276/* C6.3.32 DUP (General)
5277 *
5278 * 31 30 29 21 20 16 15 10 9 5 4 0
5279 * +---+---+-------------------+--------+-------------+------+------+
5280 * | 0 | Q | 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 0 0 1 1 | Rn | Rd |
5281 * +---+---+-------------------+--------+-------------+------+------+
5282 *
5283 * size: encoded in imm5 (see ARM ARM LowestSetBit())
5284 */
5285static void handle_simd_dupg(DisasContext *s, int is_q, int rd, int rn,
5286 int imm5)
5287{
5288 int size = ctz32(imm5);
5289 int esize = 8 << size;
5290 int elements = (is_q ? 128 : 64)/esize;
5291 int i = 0;
5292
5293 if (size > 3 || ((size == 3) && !is_q)) {
5294 unallocated_encoding(s);
5295 return;
5296 }
5297 for (i = 0; i < elements; i++) {
5298 write_vec_element(s, cpu_reg(s, rn), rd, i, size);
5299 }
5300 if (!is_q) {
5301 clear_vec_high(s, rd);
5302 }
5303}
5304
5305/* C6.3.150 INS (Element)
5306 *
5307 * 31 21 20 16 15 14 11 10 9 5 4 0
5308 * +-----------------------+--------+------------+---+------+------+
5309 * | 0 1 1 0 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd |
5310 * +-----------------------+--------+------------+---+------+------+
5311 *
5312 * size: encoded in imm5 (see ARM ARM LowestSetBit())
5313 * index: encoded in imm5<4:size+1>
5314 */
5315static void handle_simd_inse(DisasContext *s, int rd, int rn,
5316 int imm4, int imm5)
5317{
5318 int size = ctz32(imm5);
5319 int src_index, dst_index;
5320 TCGv_i64 tmp;
5321
5322 if (size > 3) {
5323 unallocated_encoding(s);
5324 return;
5325 }
5326 dst_index = extract32(imm5, 1+size, 5);
5327 src_index = extract32(imm4, size, 4);
5328
5329 tmp = tcg_temp_new_i64();
5330
5331 read_vec_element(s, tmp, rn, src_index, size);
5332 write_vec_element(s, tmp, rd, dst_index, size);
5333
5334 tcg_temp_free_i64(tmp);
5335}
5336
5337
5338/* C6.3.151 INS (General)
5339 *
5340 * 31 21 20 16 15 10 9 5 4 0
5341 * +-----------------------+--------+-------------+------+------+
5342 * | 0 1 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 0 1 1 1 | Rn | Rd |
5343 * +-----------------------+--------+-------------+------+------+
5344 *
5345 * size: encoded in imm5 (see ARM ARM LowestSetBit())
5346 * index: encoded in imm5<4:size+1>
5347 */
5348static void handle_simd_insg(DisasContext *s, int rd, int rn, int imm5)
5349{
5350 int size = ctz32(imm5);
5351 int idx;
5352
5353 if (size > 3) {
5354 unallocated_encoding(s);
5355 return;
5356 }
5357
5358 idx = extract32(imm5, 1 + size, 4 - size);
5359 write_vec_element(s, cpu_reg(s, rn), rd, idx, size);
5360}
5361
5362/*
5363 * C6.3.321 UMOV (General)
5364 * C6.3.237 SMOV (General)
5365 *
5366 * 31 30 29 21 20 16 15 12 10 9 5 4 0
5367 * +---+---+-------------------+--------+-------------+------+------+
5368 * | 0 | Q | 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 1 U 1 1 | Rn | Rd |
5369 * +---+---+-------------------+--------+-------------+------+------+
5370 *
5371 * U: unsigned when set
5372 * size: encoded in imm5 (see ARM ARM LowestSetBit())
5373 */
5374static void handle_simd_umov_smov(DisasContext *s, int is_q, int is_signed,
5375 int rn, int rd, int imm5)
5376{
5377 int size = ctz32(imm5);
5378 int element;
5379 TCGv_i64 tcg_rd;
5380
5381 /* Check for UnallocatedEncodings */
5382 if (is_signed) {
5383 if (size > 2 || (size == 2 && !is_q)) {
5384 unallocated_encoding(s);
5385 return;
5386 }
5387 } else {
5388 if (size > 3
5389 || (size < 3 && is_q)
5390 || (size == 3 && !is_q)) {
5391 unallocated_encoding(s);
5392 return;
5393 }
5394 }
5395 element = extract32(imm5, 1+size, 4);
5396
5397 tcg_rd = cpu_reg(s, rd);
5398 read_vec_element(s, tcg_rd, rn, element, size | (is_signed ? MO_SIGN : 0));
5399 if (is_signed && !is_q) {
5400 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
5401 }
5402}
5403
Alex Bennée384b26f2014-01-31 14:47:30 +00005404/* C3.6.5 AdvSIMD copy
5405 * 31 30 29 28 21 20 16 15 14 11 10 9 5 4 0
5406 * +---+---+----+-----------------+------+---+------+---+------+------+
5407 * | 0 | Q | op | 0 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd |
5408 * +---+---+----+-----------------+------+---+------+---+------+------+
5409 */
5410static void disas_simd_copy(DisasContext *s, uint32_t insn)
5411{
Alex Bennée67bb9382014-01-31 14:47:31 +00005412 int rd = extract32(insn, 0, 5);
5413 int rn = extract32(insn, 5, 5);
5414 int imm4 = extract32(insn, 11, 4);
5415 int op = extract32(insn, 29, 1);
5416 int is_q = extract32(insn, 30, 1);
5417 int imm5 = extract32(insn, 16, 5);
5418
5419 if (op) {
5420 if (is_q) {
5421 /* INS (element) */
5422 handle_simd_inse(s, rd, rn, imm4, imm5);
5423 } else {
5424 unallocated_encoding(s);
5425 }
5426 } else {
5427 switch (imm4) {
5428 case 0:
5429 /* DUP (element - vector) */
5430 handle_simd_dupe(s, is_q, rd, rn, imm5);
5431 break;
5432 case 1:
5433 /* DUP (general) */
5434 handle_simd_dupg(s, is_q, rd, rn, imm5);
5435 break;
5436 case 3:
5437 if (is_q) {
5438 /* INS (general) */
5439 handle_simd_insg(s, rd, rn, imm5);
5440 } else {
5441 unallocated_encoding(s);
5442 }
5443 break;
5444 case 5:
5445 case 7:
5446 /* UMOV/SMOV (is_q indicates 32/64; imm4 indicates signedness) */
5447 handle_simd_umov_smov(s, is_q, (imm4 == 5), rn, rd, imm5);
5448 break;
5449 default:
5450 unallocated_encoding(s);
5451 break;
5452 }
5453 }
Alex Bennée384b26f2014-01-31 14:47:30 +00005454}
5455
5456/* C3.6.6 AdvSIMD modified immediate
5457 * 31 30 29 28 19 18 16 15 12 11 10 9 5 4 0
5458 * +---+---+----+---------------------+-----+-------+----+---+-------+------+
5459 * | 0 | Q | op | 0 1 1 1 1 0 0 0 0 0 | abc | cmode | o2 | 1 | defgh | Rd |
5460 * +---+---+----+---------------------+-----+-------+----+---+-------+------+
Alex Bennéef3f8c4f2014-01-31 14:47:32 +00005461 *
5462 * There are a number of operations that can be carried out here:
5463 * MOVI - move (shifted) imm into register
5464 * MVNI - move inverted (shifted) imm into register
5465 * ORR - bitwise OR of (shifted) imm with register
5466 * BIC - bitwise clear of (shifted) imm with register
Alex Bennée384b26f2014-01-31 14:47:30 +00005467 */
5468static void disas_simd_mod_imm(DisasContext *s, uint32_t insn)
5469{
Alex Bennéef3f8c4f2014-01-31 14:47:32 +00005470 int rd = extract32(insn, 0, 5);
5471 int cmode = extract32(insn, 12, 4);
5472 int cmode_3_1 = extract32(cmode, 1, 3);
5473 int cmode_0 = extract32(cmode, 0, 1);
5474 int o2 = extract32(insn, 11, 1);
5475 uint64_t abcdefgh = extract32(insn, 5, 5) | (extract32(insn, 16, 3) << 5);
5476 bool is_neg = extract32(insn, 29, 1);
5477 bool is_q = extract32(insn, 30, 1);
5478 uint64_t imm = 0;
5479 TCGv_i64 tcg_rd, tcg_imm;
5480 int i;
5481
5482 if (o2 != 0 || ((cmode == 0xf) && is_neg && !is_q)) {
5483 unallocated_encoding(s);
5484 return;
5485 }
5486
5487 /* See AdvSIMDExpandImm() in ARM ARM */
5488 switch (cmode_3_1) {
5489 case 0: /* Replicate(Zeros(24):imm8, 2) */
5490 case 1: /* Replicate(Zeros(16):imm8:Zeros(8), 2) */
5491 case 2: /* Replicate(Zeros(8):imm8:Zeros(16), 2) */
5492 case 3: /* Replicate(imm8:Zeros(24), 2) */
5493 {
5494 int shift = cmode_3_1 * 8;
5495 imm = bitfield_replicate(abcdefgh << shift, 32);
5496 break;
5497 }
5498 case 4: /* Replicate(Zeros(8):imm8, 4) */
5499 case 5: /* Replicate(imm8:Zeros(8), 4) */
5500 {
5501 int shift = (cmode_3_1 & 0x1) * 8;
5502 imm = bitfield_replicate(abcdefgh << shift, 16);
5503 break;
5504 }
5505 case 6:
5506 if (cmode_0) {
5507 /* Replicate(Zeros(8):imm8:Ones(16), 2) */
5508 imm = (abcdefgh << 16) | 0xffff;
5509 } else {
5510 /* Replicate(Zeros(16):imm8:Ones(8), 2) */
5511 imm = (abcdefgh << 8) | 0xff;
5512 }
5513 imm = bitfield_replicate(imm, 32);
5514 break;
5515 case 7:
5516 if (!cmode_0 && !is_neg) {
5517 imm = bitfield_replicate(abcdefgh, 8);
5518 } else if (!cmode_0 && is_neg) {
5519 int i;
5520 imm = 0;
5521 for (i = 0; i < 8; i++) {
5522 if ((abcdefgh) & (1 << i)) {
5523 imm |= 0xffULL << (i * 8);
5524 }
5525 }
5526 } else if (cmode_0) {
5527 if (is_neg) {
5528 imm = (abcdefgh & 0x3f) << 48;
5529 if (abcdefgh & 0x80) {
5530 imm |= 0x8000000000000000ULL;
5531 }
5532 if (abcdefgh & 0x40) {
5533 imm |= 0x3fc0000000000000ULL;
5534 } else {
5535 imm |= 0x4000000000000000ULL;
5536 }
5537 } else {
5538 imm = (abcdefgh & 0x3f) << 19;
5539 if (abcdefgh & 0x80) {
5540 imm |= 0x80000000;
5541 }
5542 if (abcdefgh & 0x40) {
5543 imm |= 0x3e000000;
5544 } else {
5545 imm |= 0x40000000;
5546 }
5547 imm |= (imm << 32);
5548 }
5549 }
5550 break;
5551 }
5552
5553 if (cmode_3_1 != 7 && is_neg) {
5554 imm = ~imm;
5555 }
5556
5557 tcg_imm = tcg_const_i64(imm);
5558 tcg_rd = new_tmp_a64(s);
5559
5560 for (i = 0; i < 2; i++) {
5561 int foffs = i ? fp_reg_hi_offset(rd) : fp_reg_offset(rd, MO_64);
5562
5563 if (i == 1 && !is_q) {
5564 /* non-quad ops clear high half of vector */
5565 tcg_gen_movi_i64(tcg_rd, 0);
5566 } else if ((cmode & 0x9) == 0x1 || (cmode & 0xd) == 0x9) {
5567 tcg_gen_ld_i64(tcg_rd, cpu_env, foffs);
5568 if (is_neg) {
5569 /* AND (BIC) */
5570 tcg_gen_and_i64(tcg_rd, tcg_rd, tcg_imm);
5571 } else {
5572 /* ORR */
5573 tcg_gen_or_i64(tcg_rd, tcg_rd, tcg_imm);
5574 }
5575 } else {
5576 /* MOVI */
5577 tcg_gen_mov_i64(tcg_rd, tcg_imm);
5578 }
5579 tcg_gen_st_i64(tcg_rd, cpu_env, foffs);
5580 }
5581
5582 tcg_temp_free_i64(tcg_imm);
Alex Bennée384b26f2014-01-31 14:47:30 +00005583}
5584
5585/* C3.6.7 AdvSIMD scalar copy
5586 * 31 30 29 28 21 20 16 15 14 11 10 9 5 4 0
5587 * +-----+----+-----------------+------+---+------+---+------+------+
5588 * | 0 1 | op | 1 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd |
5589 * +-----+----+-----------------+------+---+------+---+------+------+
5590 */
5591static void disas_simd_scalar_copy(DisasContext *s, uint32_t insn)
5592{
Peter Maydell360a6f22014-01-31 14:47:32 +00005593 int rd = extract32(insn, 0, 5);
5594 int rn = extract32(insn, 5, 5);
5595 int imm4 = extract32(insn, 11, 4);
5596 int imm5 = extract32(insn, 16, 5);
5597 int op = extract32(insn, 29, 1);
5598
5599 if (op != 0 || imm4 != 0) {
5600 unallocated_encoding(s);
5601 return;
5602 }
5603
5604 /* DUP (element, scalar) */
5605 handle_simd_dupes(s, rd, rn, imm5);
Alex Bennée384b26f2014-01-31 14:47:30 +00005606}
5607
5608/* C3.6.8 AdvSIMD scalar pairwise
5609 * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
5610 * +-----+---+-----------+------+-----------+--------+-----+------+------+
5611 * | 0 1 | U | 1 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 | Rn | Rd |
5612 * +-----+---+-----------+------+-----------+--------+-----+------+------+
5613 */
5614static void disas_simd_scalar_pairwise(DisasContext *s, uint32_t insn)
5615{
Peter Maydell3720a7e2014-02-08 14:46:56 +00005616 int u = extract32(insn, 29, 1);
5617 int size = extract32(insn, 22, 2);
5618 int opcode = extract32(insn, 12, 5);
5619 int rn = extract32(insn, 5, 5);
5620 int rd = extract32(insn, 0, 5);
5621 TCGv_ptr fpst;
5622
5623 /* For some ops (the FP ones), size[1] is part of the encoding.
5624 * For ADDP strictly it is not but size[1] is always 1 for valid
5625 * encodings.
5626 */
5627 opcode |= (extract32(size, 1, 1) << 5);
5628
5629 switch (opcode) {
5630 case 0x3b: /* ADDP */
5631 if (u || size != 3) {
5632 unallocated_encoding(s);
5633 return;
5634 }
5635 TCGV_UNUSED_PTR(fpst);
5636 break;
5637 case 0xc: /* FMAXNMP */
5638 case 0xd: /* FADDP */
5639 case 0xf: /* FMAXP */
5640 case 0x2c: /* FMINNMP */
5641 case 0x2f: /* FMINP */
5642 /* FP op, size[0] is 32 or 64 bit */
5643 if (!u) {
5644 unallocated_encoding(s);
5645 return;
5646 }
5647 size = extract32(size, 0, 1) ? 3 : 2;
5648 fpst = get_fpstatus_ptr();
5649 break;
5650 default:
5651 unallocated_encoding(s);
5652 return;
5653 }
5654
5655 if (size == 3) {
5656 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
5657 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
5658 TCGv_i64 tcg_res = tcg_temp_new_i64();
5659
5660 read_vec_element(s, tcg_op1, rn, 0, MO_64);
5661 read_vec_element(s, tcg_op2, rn, 1, MO_64);
5662
5663 switch (opcode) {
5664 case 0x3b: /* ADDP */
5665 tcg_gen_add_i64(tcg_res, tcg_op1, tcg_op2);
5666 break;
5667 case 0xc: /* FMAXNMP */
5668 gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
5669 break;
5670 case 0xd: /* FADDP */
5671 gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
5672 break;
5673 case 0xf: /* FMAXP */
5674 gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
5675 break;
5676 case 0x2c: /* FMINNMP */
5677 gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
5678 break;
5679 case 0x2f: /* FMINP */
5680 gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
5681 break;
5682 default:
5683 g_assert_not_reached();
5684 }
5685
5686 write_fp_dreg(s, rd, tcg_res);
5687
5688 tcg_temp_free_i64(tcg_op1);
5689 tcg_temp_free_i64(tcg_op2);
5690 tcg_temp_free_i64(tcg_res);
5691 } else {
5692 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
5693 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
5694 TCGv_i32 tcg_res = tcg_temp_new_i32();
5695
5696 read_vec_element_i32(s, tcg_op1, rn, 0, MO_32);
5697 read_vec_element_i32(s, tcg_op2, rn, 1, MO_32);
5698
5699 switch (opcode) {
5700 case 0xc: /* FMAXNMP */
5701 gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
5702 break;
5703 case 0xd: /* FADDP */
5704 gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
5705 break;
5706 case 0xf: /* FMAXP */
5707 gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
5708 break;
5709 case 0x2c: /* FMINNMP */
5710 gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
5711 break;
5712 case 0x2f: /* FMINP */
5713 gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
5714 break;
5715 default:
5716 g_assert_not_reached();
5717 }
5718
5719 write_fp_sreg(s, rd, tcg_res);
5720
5721 tcg_temp_free_i32(tcg_op1);
5722 tcg_temp_free_i32(tcg_op2);
5723 tcg_temp_free_i32(tcg_res);
5724 }
5725
5726 if (!TCGV_IS_UNUSED_PTR(fpst)) {
5727 tcg_temp_free_ptr(fpst);
5728 }
Alex Bennée384b26f2014-01-31 14:47:30 +00005729}
5730
Alex Bennée4d1cef82014-01-31 14:47:37 +00005731/*
5732 * Common SSHR[RA]/USHR[RA] - Shift right (optional rounding/accumulate)
5733 *
5734 * This code is handles the common shifting code and is used by both
5735 * the vector and scalar code.
5736 */
5737static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src,
5738 TCGv_i64 tcg_rnd, bool accumulate,
5739 bool is_u, int size, int shift)
5740{
5741 bool extended_result = false;
5742 bool round = !TCGV_IS_UNUSED_I64(tcg_rnd);
5743 int ext_lshift = 0;
5744 TCGv_i64 tcg_src_hi;
5745
5746 if (round && size == 3) {
5747 extended_result = true;
5748 ext_lshift = 64 - shift;
5749 tcg_src_hi = tcg_temp_new_i64();
5750 } else if (shift == 64) {
5751 if (!accumulate && is_u) {
5752 /* result is zero */
5753 tcg_gen_movi_i64(tcg_res, 0);
5754 return;
5755 }
5756 }
5757
5758 /* Deal with the rounding step */
5759 if (round) {
5760 if (extended_result) {
5761 TCGv_i64 tcg_zero = tcg_const_i64(0);
5762 if (!is_u) {
5763 /* take care of sign extending tcg_res */
5764 tcg_gen_sari_i64(tcg_src_hi, tcg_src, 63);
5765 tcg_gen_add2_i64(tcg_src, tcg_src_hi,
5766 tcg_src, tcg_src_hi,
5767 tcg_rnd, tcg_zero);
5768 } else {
5769 tcg_gen_add2_i64(tcg_src, tcg_src_hi,
5770 tcg_src, tcg_zero,
5771 tcg_rnd, tcg_zero);
5772 }
5773 tcg_temp_free_i64(tcg_zero);
5774 } else {
5775 tcg_gen_add_i64(tcg_src, tcg_src, tcg_rnd);
5776 }
5777 }
5778
5779 /* Now do the shift right */
5780 if (round && extended_result) {
5781 /* extended case, >64 bit precision required */
5782 if (ext_lshift == 0) {
5783 /* special case, only high bits matter */
5784 tcg_gen_mov_i64(tcg_src, tcg_src_hi);
5785 } else {
5786 tcg_gen_shri_i64(tcg_src, tcg_src, shift);
5787 tcg_gen_shli_i64(tcg_src_hi, tcg_src_hi, ext_lshift);
5788 tcg_gen_or_i64(tcg_src, tcg_src, tcg_src_hi);
5789 }
5790 } else {
5791 if (is_u) {
5792 if (shift == 64) {
5793 /* essentially shifting in 64 zeros */
5794 tcg_gen_movi_i64(tcg_src, 0);
5795 } else {
5796 tcg_gen_shri_i64(tcg_src, tcg_src, shift);
5797 }
5798 } else {
5799 if (shift == 64) {
5800 /* effectively extending the sign-bit */
5801 tcg_gen_sari_i64(tcg_src, tcg_src, 63);
5802 } else {
5803 tcg_gen_sari_i64(tcg_src, tcg_src, shift);
5804 }
5805 }
5806 }
5807
5808 if (accumulate) {
5809 tcg_gen_add_i64(tcg_res, tcg_res, tcg_src);
5810 } else {
5811 tcg_gen_mov_i64(tcg_res, tcg_src);
5812 }
5813
5814 if (extended_result) {
5815 tcg_temp_free_i64(tcg_src_hi);
5816 }
5817}
5818
5819/* Common SHL/SLI - Shift left with an optional insert */
5820static void handle_shli_with_ins(TCGv_i64 tcg_res, TCGv_i64 tcg_src,
5821 bool insert, int shift)
5822{
5823 if (insert) { /* SLI */
5824 tcg_gen_deposit_i64(tcg_res, tcg_res, tcg_src, shift, 64 - shift);
5825 } else { /* SHL */
5826 tcg_gen_shli_i64(tcg_res, tcg_src, shift);
5827 }
5828}
5829
5830/* SSHR[RA]/USHR[RA] - Scalar shift right (optional rounding/accumulate) */
5831static void handle_scalar_simd_shri(DisasContext *s,
5832 bool is_u, int immh, int immb,
5833 int opcode, int rn, int rd)
5834{
5835 const int size = 3;
5836 int immhb = immh << 3 | immb;
5837 int shift = 2 * (8 << size) - immhb;
5838 bool accumulate = false;
5839 bool round = false;
5840 TCGv_i64 tcg_rn;
5841 TCGv_i64 tcg_rd;
5842 TCGv_i64 tcg_round;
5843
5844 if (!extract32(immh, 3, 1)) {
5845 unallocated_encoding(s);
5846 return;
5847 }
5848
5849 switch (opcode) {
5850 case 0x02: /* SSRA / USRA (accumulate) */
5851 accumulate = true;
5852 break;
5853 case 0x04: /* SRSHR / URSHR (rounding) */
5854 round = true;
5855 break;
5856 case 0x06: /* SRSRA / URSRA (accum + rounding) */
5857 accumulate = round = true;
5858 break;
5859 }
5860
5861 if (round) {
5862 uint64_t round_const = 1ULL << (shift - 1);
5863 tcg_round = tcg_const_i64(round_const);
5864 } else {
5865 TCGV_UNUSED_I64(tcg_round);
5866 }
5867
5868 tcg_rn = read_fp_dreg(s, rn);
5869 tcg_rd = accumulate ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
5870
5871 handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
5872 accumulate, is_u, size, shift);
5873
5874 write_fp_dreg(s, rd, tcg_rd);
5875
5876 tcg_temp_free_i64(tcg_rn);
5877 tcg_temp_free_i64(tcg_rd);
5878 if (round) {
5879 tcg_temp_free_i64(tcg_round);
5880 }
5881}
5882
5883/* SHL/SLI - Scalar shift left */
5884static void handle_scalar_simd_shli(DisasContext *s, bool insert,
5885 int immh, int immb, int opcode,
5886 int rn, int rd)
5887{
5888 int size = 32 - clz32(immh) - 1;
5889 int immhb = immh << 3 | immb;
5890 int shift = immhb - (8 << size);
5891 TCGv_i64 tcg_rn = new_tmp_a64(s);
5892 TCGv_i64 tcg_rd = new_tmp_a64(s);
5893
5894 if (!extract32(immh, 3, 1)) {
5895 unallocated_encoding(s);
5896 return;
5897 }
5898
5899 tcg_rn = read_fp_dreg(s, rn);
5900 tcg_rd = insert ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
5901
5902 handle_shli_with_ins(tcg_rd, tcg_rn, insert, shift);
5903
5904 write_fp_dreg(s, rd, tcg_rd);
5905
5906 tcg_temp_free_i64(tcg_rn);
5907 tcg_temp_free_i64(tcg_rd);
5908}
5909
Peter Maydell745849b2014-03-08 20:40:20 +00005910/* Common vector code for handling integer to FP conversion */
5911static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn,
5912 int elements, int is_signed,
5913 int fracbits, int size)
5914{
5915 bool is_double = size == 3 ? true : false;
5916 TCGv_ptr tcg_fpst = get_fpstatus_ptr();
5917 TCGv_i32 tcg_shift = tcg_const_i32(fracbits);
5918 TCGv_i64 tcg_int = tcg_temp_new_i64();
5919 TCGMemOp mop = size | (is_signed ? MO_SIGN : 0);
5920 int pass;
5921
5922 for (pass = 0; pass < elements; pass++) {
5923 read_vec_element(s, tcg_int, rn, pass, mop);
5924
5925 if (is_double) {
5926 TCGv_i64 tcg_double = tcg_temp_new_i64();
5927 if (is_signed) {
5928 gen_helper_vfp_sqtod(tcg_double, tcg_int,
5929 tcg_shift, tcg_fpst);
5930 } else {
5931 gen_helper_vfp_uqtod(tcg_double, tcg_int,
5932 tcg_shift, tcg_fpst);
5933 }
5934 if (elements == 1) {
5935 write_fp_dreg(s, rd, tcg_double);
5936 } else {
5937 write_vec_element(s, tcg_double, rd, pass, MO_64);
5938 }
5939 tcg_temp_free_i64(tcg_double);
5940 } else {
5941 TCGv_i32 tcg_single = tcg_temp_new_i32();
5942 if (is_signed) {
5943 gen_helper_vfp_sqtos(tcg_single, tcg_int,
5944 tcg_shift, tcg_fpst);
5945 } else {
5946 gen_helper_vfp_uqtos(tcg_single, tcg_int,
5947 tcg_shift, tcg_fpst);
5948 }
5949 if (elements == 1) {
5950 write_fp_sreg(s, rd, tcg_single);
5951 } else {
5952 write_vec_element_i32(s, tcg_single, rd, pass, MO_32);
5953 }
5954 tcg_temp_free_i32(tcg_single);
5955 }
5956 }
5957
5958 if (!is_double && elements == 2) {
5959 clear_vec_high(s, rd);
5960 }
5961
5962 tcg_temp_free_i64(tcg_int);
5963 tcg_temp_free_ptr(tcg_fpst);
5964 tcg_temp_free_i32(tcg_shift);
5965}
5966
5967/* UCVTF/SCVTF - Integer to FP conversion */
5968static void handle_simd_shift_intfp_conv(DisasContext *s, bool is_scalar,
5969 bool is_q, bool is_u,
5970 int immh, int immb, int opcode,
5971 int rn, int rd)
5972{
5973 bool is_double = extract32(immh, 3, 1);
5974 int size = is_double ? MO_64 : MO_32;
5975 int elements;
5976 int immhb = immh << 3 | immb;
5977 int fracbits = (is_double ? 128 : 64) - immhb;
5978
5979 if (!extract32(immh, 2, 2)) {
5980 unallocated_encoding(s);
5981 return;
5982 }
5983
5984 if (is_scalar) {
5985 elements = 1;
5986 } else {
5987 elements = is_double ? 2 : is_q ? 4 : 2;
5988 if (is_double && !is_q) {
5989 unallocated_encoding(s);
5990 return;
5991 }
5992 }
5993 /* immh == 0 would be a failure of the decode logic */
5994 g_assert(immh);
5995
5996 handle_simd_intfp_conv(s, rd, rn, elements, !is_u, fracbits, size);
5997}
5998
Alex Bennée384b26f2014-01-31 14:47:30 +00005999/* C3.6.9 AdvSIMD scalar shift by immediate
6000 * 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0
6001 * +-----+---+-------------+------+------+--------+---+------+------+
6002 * | 0 1 | U | 1 1 1 1 1 0 | immh | immb | opcode | 1 | Rn | Rd |
6003 * +-----+---+-------------+------+------+--------+---+------+------+
Alex Bennée4d1cef82014-01-31 14:47:37 +00006004 *
6005 * This is the scalar version so it works on a fixed sized registers
Alex Bennée384b26f2014-01-31 14:47:30 +00006006 */
6007static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn)
6008{
Alex Bennée4d1cef82014-01-31 14:47:37 +00006009 int rd = extract32(insn, 0, 5);
6010 int rn = extract32(insn, 5, 5);
6011 int opcode = extract32(insn, 11, 5);
6012 int immb = extract32(insn, 16, 3);
6013 int immh = extract32(insn, 19, 4);
6014 bool is_u = extract32(insn, 29, 1);
6015
6016 switch (opcode) {
6017 case 0x00: /* SSHR / USHR */
6018 case 0x02: /* SSRA / USRA */
6019 case 0x04: /* SRSHR / URSHR */
6020 case 0x06: /* SRSRA / URSRA */
6021 handle_scalar_simd_shri(s, is_u, immh, immb, opcode, rn, rd);
6022 break;
6023 case 0x0a: /* SHL / SLI */
6024 handle_scalar_simd_shli(s, is_u, immh, immb, opcode, rn, rd);
6025 break;
Peter Maydell745849b2014-03-08 20:40:20 +00006026 case 0x1c: /* SCVTF, UCVTF */
6027 handle_simd_shift_intfp_conv(s, true, false, is_u, immh, immb,
6028 opcode, rn, rd);
6029 break;
Alex Bennée4d1cef82014-01-31 14:47:37 +00006030 default:
6031 unsupported_encoding(s, insn);
6032 break;
6033 }
Alex Bennée384b26f2014-01-31 14:47:30 +00006034}
6035
6036/* C3.6.10 AdvSIMD scalar three different
6037 * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
6038 * +-----+---+-----------+------+---+------+--------+-----+------+------+
6039 * | 0 1 | U | 1 1 1 1 0 | size | 1 | Rm | opcode | 0 0 | Rn | Rd |
6040 * +-----+---+-----------+------+---+------+--------+-----+------+------+
6041 */
6042static void disas_simd_scalar_three_reg_diff(DisasContext *s, uint32_t insn)
6043{
Peter Maydellb033cd32014-02-20 10:35:49 +00006044 bool is_u = extract32(insn, 29, 1);
6045 int size = extract32(insn, 22, 2);
6046 int opcode = extract32(insn, 12, 4);
6047 int rm = extract32(insn, 16, 5);
6048 int rn = extract32(insn, 5, 5);
6049 int rd = extract32(insn, 0, 5);
6050
6051 if (is_u) {
6052 unallocated_encoding(s);
6053 return;
6054 }
6055
6056 switch (opcode) {
6057 case 0x9: /* SQDMLAL, SQDMLAL2 */
6058 case 0xb: /* SQDMLSL, SQDMLSL2 */
6059 case 0xd: /* SQDMULL, SQDMULL2 */
6060 if (size == 0 || size == 3) {
6061 unallocated_encoding(s);
6062 return;
6063 }
6064 break;
6065 default:
6066 unallocated_encoding(s);
6067 return;
6068 }
6069
6070 if (size == 2) {
6071 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
6072 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
6073 TCGv_i64 tcg_res = tcg_temp_new_i64();
6074
6075 read_vec_element(s, tcg_op1, rn, 0, MO_32 | MO_SIGN);
6076 read_vec_element(s, tcg_op2, rm, 0, MO_32 | MO_SIGN);
6077
6078 tcg_gen_mul_i64(tcg_res, tcg_op1, tcg_op2);
6079 gen_helper_neon_addl_saturate_s64(tcg_res, cpu_env, tcg_res, tcg_res);
6080
6081 switch (opcode) {
6082 case 0xd: /* SQDMULL, SQDMULL2 */
6083 break;
6084 case 0xb: /* SQDMLSL, SQDMLSL2 */
6085 tcg_gen_neg_i64(tcg_res, tcg_res);
6086 /* fall through */
6087 case 0x9: /* SQDMLAL, SQDMLAL2 */
6088 read_vec_element(s, tcg_op1, rd, 0, MO_64);
6089 gen_helper_neon_addl_saturate_s64(tcg_res, cpu_env,
6090 tcg_res, tcg_op1);
6091 break;
6092 default:
6093 g_assert_not_reached();
6094 }
6095
6096 write_fp_dreg(s, rd, tcg_res);
6097
6098 tcg_temp_free_i64(tcg_op1);
6099 tcg_temp_free_i64(tcg_op2);
6100 tcg_temp_free_i64(tcg_res);
6101 } else {
6102 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
6103 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
6104 TCGv_i64 tcg_res = tcg_temp_new_i64();
6105
6106 read_vec_element_i32(s, tcg_op1, rn, 0, MO_16);
6107 read_vec_element_i32(s, tcg_op2, rm, 0, MO_16);
6108
6109 gen_helper_neon_mull_s16(tcg_res, tcg_op1, tcg_op2);
6110 gen_helper_neon_addl_saturate_s32(tcg_res, cpu_env, tcg_res, tcg_res);
6111
6112 switch (opcode) {
6113 case 0xd: /* SQDMULL, SQDMULL2 */
6114 break;
6115 case 0xb: /* SQDMLSL, SQDMLSL2 */
6116 gen_helper_neon_negl_u32(tcg_res, tcg_res);
6117 /* fall through */
6118 case 0x9: /* SQDMLAL, SQDMLAL2 */
6119 {
6120 TCGv_i64 tcg_op3 = tcg_temp_new_i64();
6121 read_vec_element(s, tcg_op3, rd, 0, MO_32);
6122 gen_helper_neon_addl_saturate_s32(tcg_res, cpu_env,
6123 tcg_res, tcg_op3);
6124 tcg_temp_free_i64(tcg_op3);
6125 break;
6126 }
6127 default:
6128 g_assert_not_reached();
6129 }
6130
6131 tcg_gen_ext32u_i64(tcg_res, tcg_res);
6132 write_fp_dreg(s, rd, tcg_res);
6133
6134 tcg_temp_free_i32(tcg_op1);
6135 tcg_temp_free_i32(tcg_op2);
6136 tcg_temp_free_i64(tcg_res);
6137 }
Alex Bennée384b26f2014-01-31 14:47:30 +00006138}
6139
Peter Maydellb305dba2014-01-31 14:47:36 +00006140static void handle_3same_64(DisasContext *s, int opcode, bool u,
6141 TCGv_i64 tcg_rd, TCGv_i64 tcg_rn, TCGv_i64 tcg_rm)
6142{
6143 /* Handle 64x64->64 opcodes which are shared between the scalar
6144 * and vector 3-same groups. We cover every opcode where size == 3
6145 * is valid in either the three-reg-same (integer, not pairwise)
6146 * or scalar-three-reg-same groups. (Some opcodes are not yet
6147 * implemented.)
6148 */
6149 TCGCond cond;
6150
6151 switch (opcode) {
Peter Maydell6d9571f2014-02-08 14:46:55 +00006152 case 0x1: /* SQADD */
6153 if (u) {
6154 gen_helper_neon_qadd_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6155 } else {
6156 gen_helper_neon_qadd_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6157 }
6158 break;
6159 case 0x5: /* SQSUB */
6160 if (u) {
6161 gen_helper_neon_qsub_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6162 } else {
6163 gen_helper_neon_qsub_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6164 }
6165 break;
Peter Maydellb305dba2014-01-31 14:47:36 +00006166 case 0x6: /* CMGT, CMHI */
6167 /* 64 bit integer comparison, result = test ? (2^64 - 1) : 0.
6168 * We implement this using setcond (test) and then negating.
6169 */
6170 cond = u ? TCG_COND_GTU : TCG_COND_GT;
6171 do_cmop:
6172 tcg_gen_setcond_i64(cond, tcg_rd, tcg_rn, tcg_rm);
6173 tcg_gen_neg_i64(tcg_rd, tcg_rd);
6174 break;
6175 case 0x7: /* CMGE, CMHS */
6176 cond = u ? TCG_COND_GEU : TCG_COND_GE;
6177 goto do_cmop;
6178 case 0x11: /* CMTST, CMEQ */
6179 if (u) {
6180 cond = TCG_COND_EQ;
6181 goto do_cmop;
6182 }
6183 /* CMTST : test is "if (X & Y != 0)". */
6184 tcg_gen_and_i64(tcg_rd, tcg_rn, tcg_rm);
6185 tcg_gen_setcondi_i64(TCG_COND_NE, tcg_rd, tcg_rd, 0);
6186 tcg_gen_neg_i64(tcg_rd, tcg_rd);
6187 break;
Peter Maydell6d9571f2014-02-08 14:46:55 +00006188 case 0x8: /* SSHL, USHL */
6189 if (u) {
6190 gen_helper_neon_shl_u64(tcg_rd, tcg_rn, tcg_rm);
6191 } else {
6192 gen_helper_neon_shl_s64(tcg_rd, tcg_rn, tcg_rm);
6193 }
6194 break;
6195 case 0x9: /* SQSHL, UQSHL */
6196 if (u) {
6197 gen_helper_neon_qshl_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6198 } else {
6199 gen_helper_neon_qshl_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6200 }
6201 break;
6202 case 0xa: /* SRSHL, URSHL */
6203 if (u) {
6204 gen_helper_neon_rshl_u64(tcg_rd, tcg_rn, tcg_rm);
6205 } else {
6206 gen_helper_neon_rshl_s64(tcg_rd, tcg_rn, tcg_rm);
6207 }
6208 break;
6209 case 0xb: /* SQRSHL, UQRSHL */
6210 if (u) {
6211 gen_helper_neon_qrshl_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6212 } else {
6213 gen_helper_neon_qrshl_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6214 }
6215 break;
Peter Maydellb305dba2014-01-31 14:47:36 +00006216 case 0x10: /* ADD, SUB */
6217 if (u) {
6218 tcg_gen_sub_i64(tcg_rd, tcg_rn, tcg_rm);
6219 } else {
6220 tcg_gen_add_i64(tcg_rd, tcg_rn, tcg_rm);
6221 }
6222 break;
Peter Maydellb305dba2014-01-31 14:47:36 +00006223 default:
6224 g_assert_not_reached();
6225 }
6226}
6227
Peter Maydell845ea092014-01-31 14:47:37 +00006228/* Handle the 3-same-operands float operations; shared by the scalar
6229 * and vector encodings. The caller must filter out any encodings
6230 * not allocated for the encoding it is dealing with.
6231 */
6232static void handle_3same_float(DisasContext *s, int size, int elements,
6233 int fpopcode, int rd, int rn, int rm)
6234{
6235 int pass;
6236 TCGv_ptr fpst = get_fpstatus_ptr();
6237
6238 for (pass = 0; pass < elements; pass++) {
6239 if (size) {
6240 /* Double */
6241 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
6242 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
6243 TCGv_i64 tcg_res = tcg_temp_new_i64();
6244
6245 read_vec_element(s, tcg_op1, rn, pass, MO_64);
6246 read_vec_element(s, tcg_op2, rm, pass, MO_64);
6247
6248 switch (fpopcode) {
Peter Maydell057d5f62014-02-20 10:35:50 +00006249 case 0x39: /* FMLS */
6250 /* As usual for ARM, separate negation for fused multiply-add */
6251 gen_helper_vfp_negd(tcg_op1, tcg_op1);
6252 /* fall through */
6253 case 0x19: /* FMLA */
6254 read_vec_element(s, tcg_res, rd, pass, MO_64);
6255 gen_helper_vfp_muladdd(tcg_res, tcg_op1, tcg_op2,
6256 tcg_res, fpst);
6257 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006258 case 0x18: /* FMAXNM */
6259 gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
6260 break;
6261 case 0x1a: /* FADD */
6262 gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
6263 break;
Peter Maydell057d5f62014-02-20 10:35:50 +00006264 case 0x1b: /* FMULX */
6265 gen_helper_vfp_mulxd(tcg_res, tcg_op1, tcg_op2, fpst);
6266 break;
Alex Bennée8908f4d2014-02-20 10:35:49 +00006267 case 0x1c: /* FCMEQ */
6268 gen_helper_neon_ceq_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6269 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006270 case 0x1e: /* FMAX */
6271 gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
6272 break;
Peter Maydell057d5f62014-02-20 10:35:50 +00006273 case 0x1f: /* FRECPS */
6274 gen_helper_recpsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6275 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006276 case 0x38: /* FMINNM */
6277 gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
6278 break;
6279 case 0x3a: /* FSUB */
6280 gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
6281 break;
6282 case 0x3e: /* FMIN */
6283 gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
6284 break;
Peter Maydell057d5f62014-02-20 10:35:50 +00006285 case 0x3f: /* FRSQRTS */
6286 gen_helper_rsqrtsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6287 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006288 case 0x5b: /* FMUL */
6289 gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
6290 break;
Alex Bennée8908f4d2014-02-20 10:35:49 +00006291 case 0x5c: /* FCMGE */
6292 gen_helper_neon_cge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6293 break;
Peter Maydell057d5f62014-02-20 10:35:50 +00006294 case 0x5d: /* FACGE */
6295 gen_helper_neon_acge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6296 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006297 case 0x5f: /* FDIV */
6298 gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst);
6299 break;
6300 case 0x7a: /* FABD */
6301 gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
6302 gen_helper_vfp_absd(tcg_res, tcg_res);
6303 break;
Alex Bennée8908f4d2014-02-20 10:35:49 +00006304 case 0x7c: /* FCMGT */
6305 gen_helper_neon_cgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6306 break;
Peter Maydell057d5f62014-02-20 10:35:50 +00006307 case 0x7d: /* FACGT */
6308 gen_helper_neon_acgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6309 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006310 default:
6311 g_assert_not_reached();
6312 }
6313
6314 write_vec_element(s, tcg_res, rd, pass, MO_64);
6315
6316 tcg_temp_free_i64(tcg_res);
6317 tcg_temp_free_i64(tcg_op1);
6318 tcg_temp_free_i64(tcg_op2);
6319 } else {
6320 /* Single */
6321 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
6322 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
6323 TCGv_i32 tcg_res = tcg_temp_new_i32();
6324
6325 read_vec_element_i32(s, tcg_op1, rn, pass, MO_32);
6326 read_vec_element_i32(s, tcg_op2, rm, pass, MO_32);
6327
6328 switch (fpopcode) {
Peter Maydell057d5f62014-02-20 10:35:50 +00006329 case 0x39: /* FMLS */
6330 /* As usual for ARM, separate negation for fused multiply-add */
6331 gen_helper_vfp_negs(tcg_op1, tcg_op1);
6332 /* fall through */
6333 case 0x19: /* FMLA */
6334 read_vec_element_i32(s, tcg_res, rd, pass, MO_32);
6335 gen_helper_vfp_muladds(tcg_res, tcg_op1, tcg_op2,
6336 tcg_res, fpst);
6337 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006338 case 0x1a: /* FADD */
6339 gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
6340 break;
Peter Maydell057d5f62014-02-20 10:35:50 +00006341 case 0x1b: /* FMULX */
6342 gen_helper_vfp_mulxs(tcg_res, tcg_op1, tcg_op2, fpst);
6343 break;
Alex Bennée8908f4d2014-02-20 10:35:49 +00006344 case 0x1c: /* FCMEQ */
6345 gen_helper_neon_ceq_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6346 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006347 case 0x1e: /* FMAX */
6348 gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
6349 break;
Peter Maydell057d5f62014-02-20 10:35:50 +00006350 case 0x1f: /* FRECPS */
6351 gen_helper_recpsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6352 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006353 case 0x18: /* FMAXNM */
6354 gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
6355 break;
6356 case 0x38: /* FMINNM */
6357 gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
6358 break;
6359 case 0x3a: /* FSUB */
6360 gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
6361 break;
6362 case 0x3e: /* FMIN */
6363 gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
6364 break;
Peter Maydell057d5f62014-02-20 10:35:50 +00006365 case 0x3f: /* FRSQRTS */
6366 gen_helper_rsqrtsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6367 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006368 case 0x5b: /* FMUL */
6369 gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
6370 break;
Alex Bennée8908f4d2014-02-20 10:35:49 +00006371 case 0x5c: /* FCMGE */
6372 gen_helper_neon_cge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6373 break;
Peter Maydell057d5f62014-02-20 10:35:50 +00006374 case 0x5d: /* FACGE */
6375 gen_helper_neon_acge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6376 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006377 case 0x5f: /* FDIV */
6378 gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst);
6379 break;
6380 case 0x7a: /* FABD */
6381 gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
6382 gen_helper_vfp_abss(tcg_res, tcg_res);
6383 break;
Alex Bennée8908f4d2014-02-20 10:35:49 +00006384 case 0x7c: /* FCMGT */
6385 gen_helper_neon_cgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6386 break;
Peter Maydell057d5f62014-02-20 10:35:50 +00006387 case 0x7d: /* FACGT */
6388 gen_helper_neon_acgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6389 break;
Peter Maydell845ea092014-01-31 14:47:37 +00006390 default:
6391 g_assert_not_reached();
6392 }
6393
6394 if (elements == 1) {
6395 /* scalar single so clear high part */
6396 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
6397
6398 tcg_gen_extu_i32_i64(tcg_tmp, tcg_res);
6399 write_vec_element(s, tcg_tmp, rd, pass, MO_64);
6400 tcg_temp_free_i64(tcg_tmp);
6401 } else {
6402 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
6403 }
6404
6405 tcg_temp_free_i32(tcg_res);
6406 tcg_temp_free_i32(tcg_op1);
6407 tcg_temp_free_i32(tcg_op2);
6408 }
6409 }
6410
6411 tcg_temp_free_ptr(fpst);
6412
6413 if ((elements << size) < 4) {
6414 /* scalar, or non-quad vector op */
6415 clear_vec_high(s, rd);
6416 }
6417}
6418
Alex Bennée384b26f2014-01-31 14:47:30 +00006419/* C3.6.11 AdvSIMD scalar three same
6420 * 31 30 29 28 24 23 22 21 20 16 15 11 10 9 5 4 0
6421 * +-----+---+-----------+------+---+------+--------+---+------+------+
6422 * | 0 1 | U | 1 1 1 1 0 | size | 1 | Rm | opcode | 1 | Rn | Rd |
6423 * +-----+---+-----------+------+---+------+--------+---+------+------+
6424 */
6425static void disas_simd_scalar_three_reg_same(DisasContext *s, uint32_t insn)
6426{
Peter Maydellb305dba2014-01-31 14:47:36 +00006427 int rd = extract32(insn, 0, 5);
6428 int rn = extract32(insn, 5, 5);
6429 int opcode = extract32(insn, 11, 5);
6430 int rm = extract32(insn, 16, 5);
6431 int size = extract32(insn, 22, 2);
6432 bool u = extract32(insn, 29, 1);
Peter Maydellb305dba2014-01-31 14:47:36 +00006433 TCGv_i64 tcg_rd;
6434
6435 if (opcode >= 0x18) {
6436 /* Floating point: U, size[1] and opcode indicate operation */
6437 int fpopcode = opcode | (extract32(size, 1, 1) << 5) | (u << 6);
6438 switch (fpopcode) {
6439 case 0x1b: /* FMULX */
Peter Maydellb305dba2014-01-31 14:47:36 +00006440 case 0x1f: /* FRECPS */
6441 case 0x3f: /* FRSQRTS */
Peter Maydellb305dba2014-01-31 14:47:36 +00006442 case 0x5d: /* FACGE */
Peter Maydellb305dba2014-01-31 14:47:36 +00006443 case 0x7d: /* FACGT */
Alex Bennée8908f4d2014-02-20 10:35:49 +00006444 case 0x1c: /* FCMEQ */
6445 case 0x5c: /* FCMGE */
6446 case 0x7c: /* FCMGT */
Peter Maydell845ea092014-01-31 14:47:37 +00006447 case 0x7a: /* FABD */
6448 break;
Peter Maydellb305dba2014-01-31 14:47:36 +00006449 default:
6450 unallocated_encoding(s);
6451 return;
6452 }
Peter Maydell845ea092014-01-31 14:47:37 +00006453
6454 handle_3same_float(s, extract32(size, 0, 1), 1, fpopcode, rd, rn, rm);
6455 return;
Peter Maydellb305dba2014-01-31 14:47:36 +00006456 }
6457
6458 switch (opcode) {
6459 case 0x1: /* SQADD, UQADD */
6460 case 0x5: /* SQSUB, UQSUB */
Peter Maydellc0b2b5f2014-02-08 14:46:56 +00006461 case 0x9: /* SQSHL, UQSHL */
6462 case 0xb: /* SQRSHL, UQRSHL */
6463 break;
Peter Maydell6d9571f2014-02-08 14:46:55 +00006464 case 0x8: /* SSHL, USHL */
6465 case 0xa: /* SRSHL, URSHL */
Peter Maydellb305dba2014-01-31 14:47:36 +00006466 case 0x6: /* CMGT, CMHI */
6467 case 0x7: /* CMGE, CMHS */
6468 case 0x11: /* CMTST, CMEQ */
6469 case 0x10: /* ADD, SUB (vector) */
6470 if (size != 3) {
6471 unallocated_encoding(s);
6472 return;
6473 }
6474 break;
Peter Maydellb305dba2014-01-31 14:47:36 +00006475 case 0x16: /* SQDMULH, SQRDMULH (vector) */
6476 if (size != 1 && size != 2) {
6477 unallocated_encoding(s);
6478 return;
6479 }
Peter Maydellc0b2b5f2014-02-08 14:46:56 +00006480 break;
Peter Maydellb305dba2014-01-31 14:47:36 +00006481 default:
6482 unallocated_encoding(s);
6483 return;
6484 }
6485
Peter Maydellb305dba2014-01-31 14:47:36 +00006486 tcg_rd = tcg_temp_new_i64();
6487
Peter Maydellc0b2b5f2014-02-08 14:46:56 +00006488 if (size == 3) {
6489 TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
6490 TCGv_i64 tcg_rm = read_fp_dreg(s, rm);
6491
6492 handle_3same_64(s, opcode, u, tcg_rd, tcg_rn, tcg_rm);
6493 tcg_temp_free_i64(tcg_rn);
6494 tcg_temp_free_i64(tcg_rm);
6495 } else {
6496 /* Do a single operation on the lowest element in the vector.
6497 * We use the standard Neon helpers and rely on 0 OP 0 == 0 with
6498 * no side effects for all these operations.
6499 * OPTME: special-purpose helpers would avoid doing some
6500 * unnecessary work in the helper for the 8 and 16 bit cases.
6501 */
6502 NeonGenTwoOpEnvFn *genenvfn;
6503 TCGv_i32 tcg_rn = tcg_temp_new_i32();
6504 TCGv_i32 tcg_rm = tcg_temp_new_i32();
6505 TCGv_i32 tcg_rd32 = tcg_temp_new_i32();
6506
6507 read_vec_element_i32(s, tcg_rn, rn, 0, size);
6508 read_vec_element_i32(s, tcg_rm, rm, 0, size);
6509
6510 switch (opcode) {
6511 case 0x1: /* SQADD, UQADD */
6512 {
6513 static NeonGenTwoOpEnvFn * const fns[3][2] = {
6514 { gen_helper_neon_qadd_s8, gen_helper_neon_qadd_u8 },
6515 { gen_helper_neon_qadd_s16, gen_helper_neon_qadd_u16 },
6516 { gen_helper_neon_qadd_s32, gen_helper_neon_qadd_u32 },
6517 };
6518 genenvfn = fns[size][u];
6519 break;
6520 }
6521 case 0x5: /* SQSUB, UQSUB */
6522 {
6523 static NeonGenTwoOpEnvFn * const fns[3][2] = {
6524 { gen_helper_neon_qsub_s8, gen_helper_neon_qsub_u8 },
6525 { gen_helper_neon_qsub_s16, gen_helper_neon_qsub_u16 },
6526 { gen_helper_neon_qsub_s32, gen_helper_neon_qsub_u32 },
6527 };
6528 genenvfn = fns[size][u];
6529 break;
6530 }
6531 case 0x9: /* SQSHL, UQSHL */
6532 {
6533 static NeonGenTwoOpEnvFn * const fns[3][2] = {
6534 { gen_helper_neon_qshl_s8, gen_helper_neon_qshl_u8 },
6535 { gen_helper_neon_qshl_s16, gen_helper_neon_qshl_u16 },
6536 { gen_helper_neon_qshl_s32, gen_helper_neon_qshl_u32 },
6537 };
6538 genenvfn = fns[size][u];
6539 break;
6540 }
6541 case 0xb: /* SQRSHL, UQRSHL */
6542 {
6543 static NeonGenTwoOpEnvFn * const fns[3][2] = {
6544 { gen_helper_neon_qrshl_s8, gen_helper_neon_qrshl_u8 },
6545 { gen_helper_neon_qrshl_s16, gen_helper_neon_qrshl_u16 },
6546 { gen_helper_neon_qrshl_s32, gen_helper_neon_qrshl_u32 },
6547 };
6548 genenvfn = fns[size][u];
6549 break;
6550 }
6551 case 0x16: /* SQDMULH, SQRDMULH */
6552 {
6553 static NeonGenTwoOpEnvFn * const fns[2][2] = {
6554 { gen_helper_neon_qdmulh_s16, gen_helper_neon_qrdmulh_s16 },
6555 { gen_helper_neon_qdmulh_s32, gen_helper_neon_qrdmulh_s32 },
6556 };
6557 assert(size == 1 || size == 2);
6558 genenvfn = fns[size - 1][u];
6559 break;
6560 }
6561 default:
6562 g_assert_not_reached();
6563 }
6564
6565 genenvfn(tcg_rd32, cpu_env, tcg_rn, tcg_rm);
6566 tcg_gen_extu_i32_i64(tcg_rd, tcg_rd32);
6567 tcg_temp_free_i32(tcg_rd32);
6568 tcg_temp_free_i32(tcg_rn);
6569 tcg_temp_free_i32(tcg_rm);
6570 }
Peter Maydellb305dba2014-01-31 14:47:36 +00006571
6572 write_fp_dreg(s, rd, tcg_rd);
6573
Peter Maydellb305dba2014-01-31 14:47:36 +00006574 tcg_temp_free_i64(tcg_rd);
Alex Bennée384b26f2014-01-31 14:47:30 +00006575}
6576
Peter Maydelleffa8e02014-02-08 14:46:56 +00006577static void handle_2misc_64(DisasContext *s, int opcode, bool u,
6578 TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
6579{
6580 /* Handle 64->64 opcodes which are shared between the scalar and
6581 * vector 2-reg-misc groups. We cover every integer opcode where size == 3
Peter Maydellf93d0132014-02-03 23:31:52 +00006582 * is valid in either group and also the double-precision fp ops.
Peter Maydelleffa8e02014-02-08 14:46:56 +00006583 */
6584 TCGCond cond;
6585
6586 switch (opcode) {
Peter Maydell86cbc412014-02-03 23:31:51 +00006587 case 0x5: /* NOT */
6588 /* This opcode is shared with CNT and RBIT but we have earlier
6589 * enforced that size == 3 if and only if this is the NOT insn.
6590 */
6591 tcg_gen_not_i64(tcg_rd, tcg_rn);
6592 break;
Peter Maydelleffa8e02014-02-08 14:46:56 +00006593 case 0xa: /* CMLT */
6594 /* 64 bit integer comparison against zero, result is
6595 * test ? (2^64 - 1) : 0. We implement via setcond(!test) and
6596 * subtracting 1.
6597 */
6598 cond = TCG_COND_LT;
6599 do_cmop:
6600 tcg_gen_setcondi_i64(cond, tcg_rd, tcg_rn, 0);
6601 tcg_gen_neg_i64(tcg_rd, tcg_rd);
6602 break;
6603 case 0x8: /* CMGT, CMGE */
6604 cond = u ? TCG_COND_GE : TCG_COND_GT;
6605 goto do_cmop;
6606 case 0x9: /* CMEQ, CMLE */
6607 cond = u ? TCG_COND_LE : TCG_COND_EQ;
6608 goto do_cmop;
6609 case 0xb: /* ABS, NEG */
6610 if (u) {
6611 tcg_gen_neg_i64(tcg_rd, tcg_rn);
6612 } else {
6613 TCGv_i64 tcg_zero = tcg_const_i64(0);
6614 tcg_gen_neg_i64(tcg_rd, tcg_rn);
6615 tcg_gen_movcond_i64(TCG_COND_GT, tcg_rd, tcg_rn, tcg_zero,
6616 tcg_rn, tcg_rd);
6617 tcg_temp_free_i64(tcg_zero);
6618 }
6619 break;
Peter Maydellf93d0132014-02-03 23:31:52 +00006620 case 0x2f: /* FABS */
6621 gen_helper_vfp_absd(tcg_rd, tcg_rn);
6622 break;
6623 case 0x6f: /* FNEG */
6624 gen_helper_vfp_negd(tcg_rd, tcg_rn);
6625 break;
Peter Maydelleffa8e02014-02-08 14:46:56 +00006626 default:
6627 g_assert_not_reached();
6628 }
6629}
6630
Alex Bennée8908f4d2014-02-20 10:35:49 +00006631static void handle_2misc_fcmp_zero(DisasContext *s, int opcode,
6632 bool is_scalar, bool is_u, bool is_q,
6633 int size, int rn, int rd)
6634{
6635 bool is_double = (size == 3);
6636 TCGv_ptr fpst = get_fpstatus_ptr();
6637
6638 if (is_double) {
6639 TCGv_i64 tcg_op = tcg_temp_new_i64();
6640 TCGv_i64 tcg_zero = tcg_const_i64(0);
6641 TCGv_i64 tcg_res = tcg_temp_new_i64();
6642 NeonGenTwoDoubleOPFn *genfn;
6643 bool swap = false;
6644 int pass;
6645
6646 switch (opcode) {
6647 case 0x2e: /* FCMLT (zero) */
6648 swap = true;
6649 /* fallthrough */
6650 case 0x2c: /* FCMGT (zero) */
6651 genfn = gen_helper_neon_cgt_f64;
6652 break;
6653 case 0x2d: /* FCMEQ (zero) */
6654 genfn = gen_helper_neon_ceq_f64;
6655 break;
6656 case 0x6d: /* FCMLE (zero) */
6657 swap = true;
6658 /* fall through */
6659 case 0x6c: /* FCMGE (zero) */
6660 genfn = gen_helper_neon_cge_f64;
6661 break;
6662 default:
6663 g_assert_not_reached();
6664 }
6665
6666 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
6667 read_vec_element(s, tcg_op, rn, pass, MO_64);
6668 if (swap) {
6669 genfn(tcg_res, tcg_zero, tcg_op, fpst);
6670 } else {
6671 genfn(tcg_res, tcg_op, tcg_zero, fpst);
6672 }
6673 write_vec_element(s, tcg_res, rd, pass, MO_64);
6674 }
6675 if (is_scalar) {
6676 clear_vec_high(s, rd);
6677 }
6678
6679 tcg_temp_free_i64(tcg_res);
6680 tcg_temp_free_i64(tcg_zero);
6681 tcg_temp_free_i64(tcg_op);
6682 } else {
6683 TCGv_i32 tcg_op = tcg_temp_new_i32();
6684 TCGv_i32 tcg_zero = tcg_const_i32(0);
6685 TCGv_i32 tcg_res = tcg_temp_new_i32();
6686 NeonGenTwoSingleOPFn *genfn;
6687 bool swap = false;
6688 int pass, maxpasses;
6689
6690 switch (opcode) {
6691 case 0x2e: /* FCMLT (zero) */
6692 swap = true;
6693 /* fall through */
6694 case 0x2c: /* FCMGT (zero) */
6695 genfn = gen_helper_neon_cgt_f32;
6696 break;
6697 case 0x2d: /* FCMEQ (zero) */
6698 genfn = gen_helper_neon_ceq_f32;
6699 break;
6700 case 0x6d: /* FCMLE (zero) */
6701 swap = true;
6702 /* fall through */
6703 case 0x6c: /* FCMGE (zero) */
6704 genfn = gen_helper_neon_cge_f32;
6705 break;
6706 default:
6707 g_assert_not_reached();
6708 }
6709
6710 if (is_scalar) {
6711 maxpasses = 1;
6712 } else {
6713 maxpasses = is_q ? 4 : 2;
6714 }
6715
6716 for (pass = 0; pass < maxpasses; pass++) {
6717 read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
6718 if (swap) {
6719 genfn(tcg_res, tcg_zero, tcg_op, fpst);
6720 } else {
6721 genfn(tcg_res, tcg_op, tcg_zero, fpst);
6722 }
6723 if (is_scalar) {
6724 write_fp_sreg(s, rd, tcg_res);
6725 } else {
6726 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
6727 }
6728 }
6729 tcg_temp_free_i32(tcg_res);
6730 tcg_temp_free_i32(tcg_zero);
6731 tcg_temp_free_i32(tcg_op);
6732 if (!is_q && !is_scalar) {
6733 clear_vec_high(s, rd);
6734 }
6735 }
6736
6737 tcg_temp_free_ptr(fpst);
6738}
6739
Alex Bennée384b26f2014-01-31 14:47:30 +00006740/* C3.6.12 AdvSIMD scalar two reg misc
6741 * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
6742 * +-----+---+-----------+------+-----------+--------+-----+------+------+
6743 * | 0 1 | U | 1 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 | Rn | Rd |
6744 * +-----+---+-----------+------+-----------+--------+-----+------+------+
6745 */
6746static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn)
6747{
Peter Maydelleffa8e02014-02-08 14:46:56 +00006748 int rd = extract32(insn, 0, 5);
6749 int rn = extract32(insn, 5, 5);
6750 int opcode = extract32(insn, 12, 5);
6751 int size = extract32(insn, 22, 2);
6752 bool u = extract32(insn, 29, 1);
6753
6754 switch (opcode) {
6755 case 0xa: /* CMLT */
6756 if (u) {
6757 unallocated_encoding(s);
6758 return;
6759 }
6760 /* fall through */
6761 case 0x8: /* CMGT, CMGE */
6762 case 0x9: /* CMEQ, CMLE */
6763 case 0xb: /* ABS, NEG */
6764 if (size != 3) {
6765 unallocated_encoding(s);
6766 return;
6767 }
6768 break;
Alex Bennée8908f4d2014-02-20 10:35:49 +00006769 case 0xc ... 0xf:
6770 case 0x16 ... 0x1d:
6771 case 0x1f:
6772 /* Floating point: U, size[1] and opcode indicate operation;
6773 * size[0] indicates single or double precision.
6774 */
6775 opcode |= (extract32(size, 1, 1) << 5) | (u << 6);
6776 size = extract32(size, 0, 1) ? 3 : 2;
6777 switch (opcode) {
6778 case 0x2c: /* FCMGT (zero) */
6779 case 0x2d: /* FCMEQ (zero) */
6780 case 0x2e: /* FCMLT (zero) */
6781 case 0x6c: /* FCMGE (zero) */
6782 case 0x6d: /* FCMLE (zero) */
6783 handle_2misc_fcmp_zero(s, opcode, true, u, true, size, rn, rd);
6784 return;
Peter Maydell745849b2014-03-08 20:40:20 +00006785 case 0x1d: /* SCVTF */
6786 case 0x5d: /* UCVTF */
6787 {
6788 bool is_signed = (opcode == 0x1d);
6789 handle_simd_intfp_conv(s, rd, rn, 1, is_signed, 0, size);
6790 return;
6791 }
Alex Bennée8908f4d2014-02-20 10:35:49 +00006792 case 0x1a: /* FCVTNS */
6793 case 0x1b: /* FCVTMS */
6794 case 0x1c: /* FCVTAS */
Alex Bennée8908f4d2014-02-20 10:35:49 +00006795 case 0x3a: /* FCVTPS */
6796 case 0x3b: /* FCVTZS */
6797 case 0x3d: /* FRECPE */
6798 case 0x3f: /* FRECPX */
6799 case 0x56: /* FCVTXN, FCVTXN2 */
6800 case 0x5a: /* FCVTNU */
6801 case 0x5b: /* FCVTMU */
6802 case 0x5c: /* FCVTAU */
Alex Bennée8908f4d2014-02-20 10:35:49 +00006803 case 0x7a: /* FCVTPU */
6804 case 0x7b: /* FCVTZU */
6805 case 0x7d: /* FRSQRTE */
6806 unsupported_encoding(s, insn);
6807 return;
6808 default:
6809 unallocated_encoding(s);
6810 return;
6811 }
6812 break;
Peter Maydelleffa8e02014-02-08 14:46:56 +00006813 default:
6814 /* Other categories of encoding in this class:
Peter Maydelleffa8e02014-02-08 14:46:56 +00006815 * + SUQADD/USQADD/SQABS/SQNEG : size 8, 16, 32 or 64
6816 * + SQXTN/SQXTN2/SQXTUN/SQXTUN2/UQXTN/UQXTN2:
6817 * narrowing saturate ops: size 64/32/16 -> 32/16/8
6818 */
6819 unsupported_encoding(s, insn);
6820 return;
6821 }
6822
6823 if (size == 3) {
6824 TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
6825 TCGv_i64 tcg_rd = tcg_temp_new_i64();
6826
6827 handle_2misc_64(s, opcode, u, tcg_rd, tcg_rn);
6828 write_fp_dreg(s, rd, tcg_rd);
6829 tcg_temp_free_i64(tcg_rd);
6830 tcg_temp_free_i64(tcg_rn);
6831 } else {
6832 /* the 'size might not be 64' ops aren't implemented yet */
6833 g_assert_not_reached();
6834 }
Alex Bennée384b26f2014-01-31 14:47:30 +00006835}
6836
Alex Bennée4d1cef82014-01-31 14:47:37 +00006837/* SSHR[RA]/USHR[RA] - Vector shift right (optional rounding/accumulate) */
6838static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u,
6839 int immh, int immb, int opcode, int rn, int rd)
6840{
6841 int size = 32 - clz32(immh) - 1;
6842 int immhb = immh << 3 | immb;
6843 int shift = 2 * (8 << size) - immhb;
6844 bool accumulate = false;
6845 bool round = false;
6846 int dsize = is_q ? 128 : 64;
6847 int esize = 8 << size;
6848 int elements = dsize/esize;
6849 TCGMemOp memop = size | (is_u ? 0 : MO_SIGN);
6850 TCGv_i64 tcg_rn = new_tmp_a64(s);
6851 TCGv_i64 tcg_rd = new_tmp_a64(s);
6852 TCGv_i64 tcg_round;
6853 int i;
6854
6855 if (extract32(immh, 3, 1) && !is_q) {
6856 unallocated_encoding(s);
6857 return;
6858 }
6859
6860 if (size > 3 && !is_q) {
6861 unallocated_encoding(s);
6862 return;
6863 }
6864
6865 switch (opcode) {
6866 case 0x02: /* SSRA / USRA (accumulate) */
6867 accumulate = true;
6868 break;
6869 case 0x04: /* SRSHR / URSHR (rounding) */
6870 round = true;
6871 break;
6872 case 0x06: /* SRSRA / URSRA (accum + rounding) */
6873 accumulate = round = true;
6874 break;
6875 }
6876
6877 if (round) {
6878 uint64_t round_const = 1ULL << (shift - 1);
6879 tcg_round = tcg_const_i64(round_const);
6880 } else {
6881 TCGV_UNUSED_I64(tcg_round);
6882 }
6883
6884 for (i = 0; i < elements; i++) {
6885 read_vec_element(s, tcg_rn, rn, i, memop);
6886 if (accumulate) {
6887 read_vec_element(s, tcg_rd, rd, i, memop);
6888 }
6889
6890 handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
6891 accumulate, is_u, size, shift);
6892
6893 write_vec_element(s, tcg_rd, rd, i, size);
6894 }
6895
6896 if (!is_q) {
6897 clear_vec_high(s, rd);
6898 }
6899
6900 if (round) {
6901 tcg_temp_free_i64(tcg_round);
6902 }
6903}
6904
6905/* SHL/SLI - Vector shift left */
6906static void handle_vec_simd_shli(DisasContext *s, bool is_q, bool insert,
6907 int immh, int immb, int opcode, int rn, int rd)
6908{
6909 int size = 32 - clz32(immh) - 1;
6910 int immhb = immh << 3 | immb;
6911 int shift = immhb - (8 << size);
6912 int dsize = is_q ? 128 : 64;
6913 int esize = 8 << size;
6914 int elements = dsize/esize;
6915 TCGv_i64 tcg_rn = new_tmp_a64(s);
6916 TCGv_i64 tcg_rd = new_tmp_a64(s);
6917 int i;
6918
6919 if (extract32(immh, 3, 1) && !is_q) {
6920 unallocated_encoding(s);
6921 return;
6922 }
6923
6924 if (size > 3 && !is_q) {
6925 unallocated_encoding(s);
6926 return;
6927 }
6928
6929 for (i = 0; i < elements; i++) {
6930 read_vec_element(s, tcg_rn, rn, i, size);
6931 if (insert) {
6932 read_vec_element(s, tcg_rd, rd, i, size);
6933 }
6934
6935 handle_shli_with_ins(tcg_rd, tcg_rn, insert, shift);
6936
6937 write_vec_element(s, tcg_rd, rd, i, size);
6938 }
6939
6940 if (!is_q) {
6941 clear_vec_high(s, rd);
6942 }
6943}
6944
6945/* USHLL/SHLL - Vector shift left with widening */
6946static void handle_vec_simd_wshli(DisasContext *s, bool is_q, bool is_u,
6947 int immh, int immb, int opcode, int rn, int rd)
6948{
6949 int size = 32 - clz32(immh) - 1;
6950 int immhb = immh << 3 | immb;
6951 int shift = immhb - (8 << size);
6952 int dsize = 64;
6953 int esize = 8 << size;
6954 int elements = dsize/esize;
6955 TCGv_i64 tcg_rn = new_tmp_a64(s);
6956 TCGv_i64 tcg_rd = new_tmp_a64(s);
6957 int i;
6958
6959 if (size >= 3) {
6960 unallocated_encoding(s);
6961 return;
6962 }
6963
6964 /* For the LL variants the store is larger than the load,
6965 * so if rd == rn we would overwrite parts of our input.
6966 * So load everything right now and use shifts in the main loop.
6967 */
6968 read_vec_element(s, tcg_rn, rn, is_q ? 1 : 0, MO_64);
6969
6970 for (i = 0; i < elements; i++) {
6971 tcg_gen_shri_i64(tcg_rd, tcg_rn, i * esize);
6972 ext_and_shift_reg(tcg_rd, tcg_rd, size | (!is_u << 2), 0);
6973 tcg_gen_shli_i64(tcg_rd, tcg_rd, shift);
6974 write_vec_element(s, tcg_rd, rd, i, size + 1);
6975 }
6976}
6977
Alex Bennée384b26f2014-01-31 14:47:30 +00006978/* C3.6.14 AdvSIMD shift by immediate
6979 * 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0
6980 * +---+---+---+-------------+------+------+--------+---+------+------+
6981 * | 0 | Q | U | 0 1 1 1 1 0 | immh | immb | opcode | 1 | Rn | Rd |
6982 * +---+---+---+-------------+------+------+--------+---+------+------+
6983 */
6984static void disas_simd_shift_imm(DisasContext *s, uint32_t insn)
6985{
Alex Bennée4d1cef82014-01-31 14:47:37 +00006986 int rd = extract32(insn, 0, 5);
6987 int rn = extract32(insn, 5, 5);
6988 int opcode = extract32(insn, 11, 5);
6989 int immb = extract32(insn, 16, 3);
6990 int immh = extract32(insn, 19, 4);
6991 bool is_u = extract32(insn, 29, 1);
6992 bool is_q = extract32(insn, 30, 1);
6993
6994 switch (opcode) {
6995 case 0x00: /* SSHR / USHR */
6996 case 0x02: /* SSRA / USRA (accumulate) */
6997 case 0x04: /* SRSHR / URSHR (rounding) */
6998 case 0x06: /* SRSRA / URSRA (accum + rounding) */
6999 handle_vec_simd_shri(s, is_q, is_u, immh, immb, opcode, rn, rd);
7000 break;
7001 case 0x0a: /* SHL / SLI */
7002 handle_vec_simd_shli(s, is_q, is_u, immh, immb, opcode, rn, rd);
7003 break;
7004 case 0x14: /* SSHLL / USHLL */
7005 handle_vec_simd_wshli(s, is_q, is_u, immh, immb, opcode, rn, rd);
7006 break;
Peter Maydell745849b2014-03-08 20:40:20 +00007007 case 0x1c: /* SCVTF / UCVTF */
7008 handle_simd_shift_intfp_conv(s, false, is_q, is_u, immh, immb,
7009 opcode, rn, rd);
7010 break;
7011 case 0x1f: /* FCVTZS/ FCVTZU */
7012 unsupported_encoding(s, insn);
7013 return;
Alex Bennée4d1cef82014-01-31 14:47:37 +00007014 default:
Peter Maydell745849b2014-03-08 20:40:20 +00007015 /* We don't currently implement any of the Narrow or
7016 * saturating shifts.
Alex Bennée4d1cef82014-01-31 14:47:37 +00007017 */
7018 unsupported_encoding(s, insn);
7019 return;
7020 }
Alex Bennée384b26f2014-01-31 14:47:30 +00007021}
7022
Peter Maydell70d7f982014-02-20 10:35:55 +00007023/* Generate code to do a "long" addition or subtraction, ie one done in
7024 * TCGv_i64 on vector lanes twice the width specified by size.
7025 */
7026static void gen_neon_addl(int size, bool is_sub, TCGv_i64 tcg_res,
7027 TCGv_i64 tcg_op1, TCGv_i64 tcg_op2)
7028{
7029 static NeonGenTwo64OpFn * const fns[3][2] = {
7030 { gen_helper_neon_addl_u16, gen_helper_neon_subl_u16 },
7031 { gen_helper_neon_addl_u32, gen_helper_neon_subl_u32 },
7032 { tcg_gen_add_i64, tcg_gen_sub_i64 },
7033 };
7034 NeonGenTwo64OpFn *genfn;
7035 assert(size < 3);
7036
7037 genfn = fns[size][is_sub];
7038 genfn(tcg_res, tcg_op1, tcg_op2);
7039}
7040
Peter Maydella08582f2014-01-31 14:47:36 +00007041static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size,
7042 int opcode, int rd, int rn, int rm)
7043{
7044 /* 3-reg-different widening insns: 64 x 64 -> 128 */
7045 TCGv_i64 tcg_res[2];
7046 int pass, accop;
7047
7048 tcg_res[0] = tcg_temp_new_i64();
7049 tcg_res[1] = tcg_temp_new_i64();
7050
7051 /* Does this op do an adding accumulate, a subtracting accumulate,
7052 * or no accumulate at all?
7053 */
7054 switch (opcode) {
7055 case 5:
7056 case 8:
7057 case 9:
7058 accop = 1;
7059 break;
7060 case 10:
7061 case 11:
7062 accop = -1;
7063 break;
7064 default:
7065 accop = 0;
7066 break;
7067 }
7068
7069 if (accop != 0) {
7070 read_vec_element(s, tcg_res[0], rd, 0, MO_64);
7071 read_vec_element(s, tcg_res[1], rd, 1, MO_64);
7072 }
7073
7074 /* size == 2 means two 32x32->64 operations; this is worth special
7075 * casing because we can generally handle it inline.
7076 */
7077 if (size == 2) {
7078 for (pass = 0; pass < 2; pass++) {
7079 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7080 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7081 TCGv_i64 tcg_passres;
7082 TCGMemOp memop = MO_32 | (is_u ? 0 : MO_SIGN);
7083
7084 int elt = pass + is_q * 2;
7085
7086 read_vec_element(s, tcg_op1, rn, elt, memop);
7087 read_vec_element(s, tcg_op2, rm, elt, memop);
7088
7089 if (accop == 0) {
7090 tcg_passres = tcg_res[pass];
7091 } else {
7092 tcg_passres = tcg_temp_new_i64();
7093 }
7094
7095 switch (opcode) {
Peter Maydell70d7f982014-02-20 10:35:55 +00007096 case 0: /* SADDL, SADDL2, UADDL, UADDL2 */
7097 tcg_gen_add_i64(tcg_passres, tcg_op1, tcg_op2);
7098 break;
7099 case 2: /* SSUBL, SSUBL2, USUBL, USUBL2 */
7100 tcg_gen_sub_i64(tcg_passres, tcg_op1, tcg_op2);
7101 break;
Peter Maydell0ae39322014-01-31 14:47:36 +00007102 case 5: /* SABAL, SABAL2, UABAL, UABAL2 */
7103 case 7: /* SABDL, SABDL2, UABDL, UABDL2 */
7104 {
7105 TCGv_i64 tcg_tmp1 = tcg_temp_new_i64();
7106 TCGv_i64 tcg_tmp2 = tcg_temp_new_i64();
7107
7108 tcg_gen_sub_i64(tcg_tmp1, tcg_op1, tcg_op2);
7109 tcg_gen_sub_i64(tcg_tmp2, tcg_op2, tcg_op1);
7110 tcg_gen_movcond_i64(is_u ? TCG_COND_GEU : TCG_COND_GE,
7111 tcg_passres,
7112 tcg_op1, tcg_op2, tcg_tmp1, tcg_tmp2);
7113 tcg_temp_free_i64(tcg_tmp1);
7114 tcg_temp_free_i64(tcg_tmp2);
7115 break;
7116 }
Peter Maydella08582f2014-01-31 14:47:36 +00007117 case 8: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
7118 case 10: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
7119 case 12: /* UMULL, UMULL2, SMULL, SMULL2 */
7120 tcg_gen_mul_i64(tcg_passres, tcg_op1, tcg_op2);
7121 break;
Peter Maydell70d7f982014-02-20 10:35:55 +00007122 case 9: /* SQDMLAL, SQDMLAL2 */
7123 case 11: /* SQDMLSL, SQDMLSL2 */
7124 case 13: /* SQDMULL, SQDMULL2 */
7125 tcg_gen_mul_i64(tcg_passres, tcg_op1, tcg_op2);
7126 gen_helper_neon_addl_saturate_s64(tcg_passres, cpu_env,
7127 tcg_passres, tcg_passres);
7128 break;
Peter Maydella08582f2014-01-31 14:47:36 +00007129 default:
7130 g_assert_not_reached();
7131 }
7132
Peter Maydell70d7f982014-02-20 10:35:55 +00007133 if (opcode == 9 || opcode == 11) {
7134 /* saturating accumulate ops */
7135 if (accop < 0) {
7136 tcg_gen_neg_i64(tcg_passres, tcg_passres);
7137 }
7138 gen_helper_neon_addl_saturate_s64(tcg_res[pass], cpu_env,
7139 tcg_res[pass], tcg_passres);
7140 } else if (accop > 0) {
Peter Maydella08582f2014-01-31 14:47:36 +00007141 tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
Peter Maydella08582f2014-01-31 14:47:36 +00007142 } else if (accop < 0) {
7143 tcg_gen_sub_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
Peter Maydell70d7f982014-02-20 10:35:55 +00007144 }
7145
7146 if (accop != 0) {
Peter Maydella08582f2014-01-31 14:47:36 +00007147 tcg_temp_free_i64(tcg_passres);
7148 }
7149
7150 tcg_temp_free_i64(tcg_op1);
7151 tcg_temp_free_i64(tcg_op2);
7152 }
7153 } else {
7154 /* size 0 or 1, generally helper functions */
7155 for (pass = 0; pass < 2; pass++) {
7156 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
7157 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
7158 TCGv_i64 tcg_passres;
7159 int elt = pass + is_q * 2;
7160
7161 read_vec_element_i32(s, tcg_op1, rn, elt, MO_32);
7162 read_vec_element_i32(s, tcg_op2, rm, elt, MO_32);
7163
7164 if (accop == 0) {
7165 tcg_passres = tcg_res[pass];
7166 } else {
7167 tcg_passres = tcg_temp_new_i64();
7168 }
7169
7170 switch (opcode) {
Peter Maydell70d7f982014-02-20 10:35:55 +00007171 case 0: /* SADDL, SADDL2, UADDL, UADDL2 */
7172 case 2: /* SSUBL, SSUBL2, USUBL, USUBL2 */
7173 {
7174 TCGv_i64 tcg_op2_64 = tcg_temp_new_i64();
7175 static NeonGenWidenFn * const widenfns[2][2] = {
7176 { gen_helper_neon_widen_s8, gen_helper_neon_widen_u8 },
7177 { gen_helper_neon_widen_s16, gen_helper_neon_widen_u16 },
7178 };
7179 NeonGenWidenFn *widenfn = widenfns[size][is_u];
7180
7181 widenfn(tcg_op2_64, tcg_op2);
7182 widenfn(tcg_passres, tcg_op1);
7183 gen_neon_addl(size, (opcode == 2), tcg_passres,
7184 tcg_passres, tcg_op2_64);
7185 tcg_temp_free_i64(tcg_op2_64);
7186 break;
7187 }
Peter Maydell0ae39322014-01-31 14:47:36 +00007188 case 5: /* SABAL, SABAL2, UABAL, UABAL2 */
7189 case 7: /* SABDL, SABDL2, UABDL, UABDL2 */
7190 if (size == 0) {
7191 if (is_u) {
7192 gen_helper_neon_abdl_u16(tcg_passres, tcg_op1, tcg_op2);
7193 } else {
7194 gen_helper_neon_abdl_s16(tcg_passres, tcg_op1, tcg_op2);
7195 }
7196 } else {
7197 if (is_u) {
7198 gen_helper_neon_abdl_u32(tcg_passres, tcg_op1, tcg_op2);
7199 } else {
7200 gen_helper_neon_abdl_s32(tcg_passres, tcg_op1, tcg_op2);
7201 }
7202 }
7203 break;
Peter Maydella08582f2014-01-31 14:47:36 +00007204 case 8: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
7205 case 10: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
7206 case 12: /* UMULL, UMULL2, SMULL, SMULL2 */
7207 if (size == 0) {
7208 if (is_u) {
7209 gen_helper_neon_mull_u8(tcg_passres, tcg_op1, tcg_op2);
7210 } else {
7211 gen_helper_neon_mull_s8(tcg_passres, tcg_op1, tcg_op2);
7212 }
7213 } else {
7214 if (is_u) {
7215 gen_helper_neon_mull_u16(tcg_passres, tcg_op1, tcg_op2);
7216 } else {
7217 gen_helper_neon_mull_s16(tcg_passres, tcg_op1, tcg_op2);
7218 }
7219 }
7220 break;
Peter Maydell70d7f982014-02-20 10:35:55 +00007221 case 9: /* SQDMLAL, SQDMLAL2 */
7222 case 11: /* SQDMLSL, SQDMLSL2 */
7223 case 13: /* SQDMULL, SQDMULL2 */
7224 assert(size == 1);
7225 gen_helper_neon_mull_s16(tcg_passres, tcg_op1, tcg_op2);
7226 gen_helper_neon_addl_saturate_s32(tcg_passres, cpu_env,
7227 tcg_passres, tcg_passres);
7228 break;
Peter Maydell6c13ec22014-02-27 12:03:17 +00007229 case 14: /* PMULL */
7230 assert(size == 0);
7231 gen_helper_neon_mull_p8(tcg_passres, tcg_op1, tcg_op2);
7232 break;
Peter Maydella08582f2014-01-31 14:47:36 +00007233 default:
7234 g_assert_not_reached();
7235 }
7236 tcg_temp_free_i32(tcg_op1);
7237 tcg_temp_free_i32(tcg_op2);
7238
Peter Maydell70d7f982014-02-20 10:35:55 +00007239 if (accop != 0) {
7240 if (opcode == 9 || opcode == 11) {
7241 /* saturating accumulate ops */
7242 if (accop < 0) {
7243 gen_helper_neon_negl_u32(tcg_passres, tcg_passres);
7244 }
7245 gen_helper_neon_addl_saturate_s32(tcg_res[pass], cpu_env,
7246 tcg_res[pass],
7247 tcg_passres);
Peter Maydella08582f2014-01-31 14:47:36 +00007248 } else {
Peter Maydell70d7f982014-02-20 10:35:55 +00007249 gen_neon_addl(size, (accop < 0), tcg_res[pass],
7250 tcg_res[pass], tcg_passres);
Peter Maydella08582f2014-01-31 14:47:36 +00007251 }
7252 tcg_temp_free_i64(tcg_passres);
7253 }
7254 }
7255 }
7256
7257 write_vec_element(s, tcg_res[0], rd, 0, MO_64);
7258 write_vec_element(s, tcg_res[1], rd, 1, MO_64);
7259 tcg_temp_free_i64(tcg_res[0]);
7260 tcg_temp_free_i64(tcg_res[1]);
7261}
7262
Peter Maydelldfc15c72014-02-20 10:35:56 +00007263static void handle_3rd_wide(DisasContext *s, int is_q, int is_u, int size,
7264 int opcode, int rd, int rn, int rm)
7265{
7266 TCGv_i64 tcg_res[2];
7267 int part = is_q ? 2 : 0;
7268 int pass;
7269
7270 for (pass = 0; pass < 2; pass++) {
7271 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7272 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
7273 TCGv_i64 tcg_op2_wide = tcg_temp_new_i64();
7274 static NeonGenWidenFn * const widenfns[3][2] = {
7275 { gen_helper_neon_widen_s8, gen_helper_neon_widen_u8 },
7276 { gen_helper_neon_widen_s16, gen_helper_neon_widen_u16 },
7277 { tcg_gen_ext_i32_i64, tcg_gen_extu_i32_i64 },
7278 };
7279 NeonGenWidenFn *widenfn = widenfns[size][is_u];
7280
7281 read_vec_element(s, tcg_op1, rn, pass, MO_64);
7282 read_vec_element_i32(s, tcg_op2, rm, part + pass, MO_32);
7283 widenfn(tcg_op2_wide, tcg_op2);
7284 tcg_temp_free_i32(tcg_op2);
7285 tcg_res[pass] = tcg_temp_new_i64();
7286 gen_neon_addl(size, (opcode == 3),
7287 tcg_res[pass], tcg_op1, tcg_op2_wide);
7288 tcg_temp_free_i64(tcg_op1);
7289 tcg_temp_free_i64(tcg_op2_wide);
7290 }
7291
7292 for (pass = 0; pass < 2; pass++) {
7293 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
7294 tcg_temp_free_i64(tcg_res[pass]);
7295 }
7296}
7297
Peter Maydelle4b998d2014-02-20 10:35:56 +00007298static void do_narrow_high_u32(TCGv_i32 res, TCGv_i64 in)
7299{
7300 tcg_gen_shri_i64(in, in, 32);
7301 tcg_gen_trunc_i64_i32(res, in);
7302}
7303
7304static void do_narrow_round_high_u32(TCGv_i32 res, TCGv_i64 in)
7305{
7306 tcg_gen_addi_i64(in, in, 1U << 31);
7307 do_narrow_high_u32(res, in);
7308}
7309
7310static void handle_3rd_narrowing(DisasContext *s, int is_q, int is_u, int size,
7311 int opcode, int rd, int rn, int rm)
7312{
7313 TCGv_i32 tcg_res[2];
7314 int part = is_q ? 2 : 0;
7315 int pass;
7316
7317 for (pass = 0; pass < 2; pass++) {
7318 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7319 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7320 TCGv_i64 tcg_wideres = tcg_temp_new_i64();
7321 static NeonGenNarrowFn * const narrowfns[3][2] = {
7322 { gen_helper_neon_narrow_high_u8,
7323 gen_helper_neon_narrow_round_high_u8 },
7324 { gen_helper_neon_narrow_high_u16,
7325 gen_helper_neon_narrow_round_high_u16 },
7326 { do_narrow_high_u32, do_narrow_round_high_u32 },
7327 };
7328 NeonGenNarrowFn *gennarrow = narrowfns[size][is_u];
7329
7330 read_vec_element(s, tcg_op1, rn, pass, MO_64);
7331 read_vec_element(s, tcg_op2, rm, pass, MO_64);
7332
7333 gen_neon_addl(size, (opcode == 6), tcg_wideres, tcg_op1, tcg_op2);
7334
7335 tcg_temp_free_i64(tcg_op1);
7336 tcg_temp_free_i64(tcg_op2);
7337
7338 tcg_res[pass] = tcg_temp_new_i32();
7339 gennarrow(tcg_res[pass], tcg_wideres);
7340 tcg_temp_free_i64(tcg_wideres);
7341 }
7342
7343 for (pass = 0; pass < 2; pass++) {
7344 write_vec_element_i32(s, tcg_res[pass], rd, pass + part, MO_32);
7345 tcg_temp_free_i32(tcg_res[pass]);
7346 }
7347 if (!is_q) {
7348 clear_vec_high(s, rd);
7349 }
7350}
7351
Peter Maydell6c13ec22014-02-27 12:03:17 +00007352static void handle_pmull_64(DisasContext *s, int is_q, int rd, int rn, int rm)
7353{
7354 /* PMULL of 64 x 64 -> 128 is an odd special case because it
7355 * is the only three-reg-diff instruction which produces a
7356 * 128-bit wide result from a single operation. However since
7357 * it's possible to calculate the two halves more or less
7358 * separately we just use two helper calls.
7359 */
7360 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7361 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7362 TCGv_i64 tcg_res = tcg_temp_new_i64();
7363
7364 read_vec_element(s, tcg_op1, rn, is_q, MO_64);
7365 read_vec_element(s, tcg_op2, rm, is_q, MO_64);
7366 gen_helper_neon_pmull_64_lo(tcg_res, tcg_op1, tcg_op2);
7367 write_vec_element(s, tcg_res, rd, 0, MO_64);
7368 gen_helper_neon_pmull_64_hi(tcg_res, tcg_op1, tcg_op2);
7369 write_vec_element(s, tcg_res, rd, 1, MO_64);
7370
7371 tcg_temp_free_i64(tcg_op1);
7372 tcg_temp_free_i64(tcg_op2);
7373 tcg_temp_free_i64(tcg_res);
7374}
7375
Alex Bennée384b26f2014-01-31 14:47:30 +00007376/* C3.6.15 AdvSIMD three different
7377 * 31 30 29 28 24 23 22 21 20 16 15 12 11 10 9 5 4 0
7378 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
7379 * | 0 | Q | U | 0 1 1 1 0 | size | 1 | Rm | opcode | 0 0 | Rn | Rd |
7380 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
7381 */
7382static void disas_simd_three_reg_diff(DisasContext *s, uint32_t insn)
7383{
Peter Maydella08582f2014-01-31 14:47:36 +00007384 /* Instructions in this group fall into three basic classes
7385 * (in each case with the operation working on each element in
7386 * the input vectors):
7387 * (1) widening 64 x 64 -> 128 (with possibly Vd as an extra
7388 * 128 bit input)
7389 * (2) wide 64 x 128 -> 128
7390 * (3) narrowing 128 x 128 -> 64
7391 * Here we do initial decode, catch unallocated cases and
7392 * dispatch to separate functions for each class.
7393 */
7394 int is_q = extract32(insn, 30, 1);
7395 int is_u = extract32(insn, 29, 1);
7396 int size = extract32(insn, 22, 2);
7397 int opcode = extract32(insn, 12, 4);
7398 int rm = extract32(insn, 16, 5);
7399 int rn = extract32(insn, 5, 5);
7400 int rd = extract32(insn, 0, 5);
7401
7402 switch (opcode) {
7403 case 1: /* SADDW, SADDW2, UADDW, UADDW2 */
7404 case 3: /* SSUBW, SSUBW2, USUBW, USUBW2 */
7405 /* 64 x 128 -> 128 */
Peter Maydelldfc15c72014-02-20 10:35:56 +00007406 if (size == 3) {
7407 unallocated_encoding(s);
7408 return;
7409 }
7410 handle_3rd_wide(s, is_q, is_u, size, opcode, rd, rn, rm);
Peter Maydella08582f2014-01-31 14:47:36 +00007411 break;
7412 case 4: /* ADDHN, ADDHN2, RADDHN, RADDHN2 */
7413 case 6: /* SUBHN, SUBHN2, RSUBHN, RSUBHN2 */
7414 /* 128 x 128 -> 64 */
Peter Maydelle4b998d2014-02-20 10:35:56 +00007415 if (size == 3) {
7416 unallocated_encoding(s);
7417 return;
7418 }
7419 handle_3rd_narrowing(s, is_q, is_u, size, opcode, rd, rn, rm);
Peter Maydella08582f2014-01-31 14:47:36 +00007420 break;
Peter Maydell70d7f982014-02-20 10:35:55 +00007421 case 14: /* PMULL, PMULL2 */
7422 if (is_u || size == 1 || size == 2) {
7423 unallocated_encoding(s);
7424 return;
7425 }
Peter Maydell6c13ec22014-02-27 12:03:17 +00007426 if (size == 3) {
7427 if (!arm_dc_feature(s, ARM_FEATURE_V8_AES)) {
7428 unallocated_encoding(s);
7429 return;
7430 }
7431 handle_pmull_64(s, is_q, rd, rn, rm);
7432 return;
7433 }
7434 goto is_widening;
Peter Maydell13caf1f2014-02-20 10:35:55 +00007435 case 9: /* SQDMLAL, SQDMLAL2 */
7436 case 11: /* SQDMLSL, SQDMLSL2 */
7437 case 13: /* SQDMULL, SQDMULL2 */
Peter Maydell70d7f982014-02-20 10:35:55 +00007438 if (is_u || size == 0) {
Peter Maydella08582f2014-01-31 14:47:36 +00007439 unallocated_encoding(s);
7440 return;
7441 }
7442 /* fall through */
Peter Maydell13caf1f2014-02-20 10:35:55 +00007443 case 0: /* SADDL, SADDL2, UADDL, UADDL2 */
7444 case 2: /* SSUBL, SSUBL2, USUBL, USUBL2 */
Peter Maydell13caf1f2014-02-20 10:35:55 +00007445 case 5: /* SABAL, SABAL2, UABAL, UABAL2 */
7446 case 7: /* SABDL, SABDL2, UABDL, UABDL2 */
7447 case 8: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
7448 case 10: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
7449 case 12: /* SMULL, SMULL2, UMULL, UMULL2 */
Peter Maydella08582f2014-01-31 14:47:36 +00007450 /* 64 x 64 -> 128 */
7451 if (size == 3) {
7452 unallocated_encoding(s);
7453 return;
7454 }
Peter Maydell6c13ec22014-02-27 12:03:17 +00007455 is_widening:
Peter Maydella08582f2014-01-31 14:47:36 +00007456 handle_3rd_widening(s, is_q, is_u, size, opcode, rd, rn, rm);
7457 break;
7458 default:
7459 /* opcode 15 not allocated */
7460 unallocated_encoding(s);
7461 break;
7462 }
Alex Bennée384b26f2014-01-31 14:47:30 +00007463}
7464
Peter Maydelle1cea112014-01-31 14:47:37 +00007465/* Logic op (opcode == 3) subgroup of C3.6.16. */
7466static void disas_simd_3same_logic(DisasContext *s, uint32_t insn)
7467{
Peter Maydell956d2722014-01-31 14:47:37 +00007468 int rd = extract32(insn, 0, 5);
7469 int rn = extract32(insn, 5, 5);
7470 int rm = extract32(insn, 16, 5);
7471 int size = extract32(insn, 22, 2);
7472 bool is_u = extract32(insn, 29, 1);
7473 bool is_q = extract32(insn, 30, 1);
7474 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7475 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7476 TCGv_i64 tcg_res[2];
7477 int pass;
7478
7479 tcg_res[0] = tcg_temp_new_i64();
7480 tcg_res[1] = tcg_temp_new_i64();
7481
7482 for (pass = 0; pass < (is_q ? 2 : 1); pass++) {
7483 read_vec_element(s, tcg_op1, rn, pass, MO_64);
7484 read_vec_element(s, tcg_op2, rm, pass, MO_64);
7485
7486 if (!is_u) {
7487 switch (size) {
7488 case 0: /* AND */
7489 tcg_gen_and_i64(tcg_res[pass], tcg_op1, tcg_op2);
7490 break;
7491 case 1: /* BIC */
7492 tcg_gen_andc_i64(tcg_res[pass], tcg_op1, tcg_op2);
7493 break;
7494 case 2: /* ORR */
7495 tcg_gen_or_i64(tcg_res[pass], tcg_op1, tcg_op2);
7496 break;
7497 case 3: /* ORN */
7498 tcg_gen_orc_i64(tcg_res[pass], tcg_op1, tcg_op2);
7499 break;
7500 }
7501 } else {
7502 if (size != 0) {
7503 /* B* ops need res loaded to operate on */
7504 read_vec_element(s, tcg_res[pass], rd, pass, MO_64);
7505 }
7506
7507 switch (size) {
7508 case 0: /* EOR */
7509 tcg_gen_xor_i64(tcg_res[pass], tcg_op1, tcg_op2);
7510 break;
7511 case 1: /* BSL bitwise select */
7512 tcg_gen_xor_i64(tcg_op1, tcg_op1, tcg_op2);
7513 tcg_gen_and_i64(tcg_op1, tcg_op1, tcg_res[pass]);
7514 tcg_gen_xor_i64(tcg_res[pass], tcg_op2, tcg_op1);
7515 break;
7516 case 2: /* BIT, bitwise insert if true */
7517 tcg_gen_xor_i64(tcg_op1, tcg_op1, tcg_res[pass]);
7518 tcg_gen_and_i64(tcg_op1, tcg_op1, tcg_op2);
7519 tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
7520 break;
7521 case 3: /* BIF, bitwise insert if false */
7522 tcg_gen_xor_i64(tcg_op1, tcg_op1, tcg_res[pass]);
7523 tcg_gen_andc_i64(tcg_op1, tcg_op1, tcg_op2);
7524 tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
7525 break;
7526 }
7527 }
7528 }
7529
7530 write_vec_element(s, tcg_res[0], rd, 0, MO_64);
7531 if (!is_q) {
7532 tcg_gen_movi_i64(tcg_res[1], 0);
7533 }
7534 write_vec_element(s, tcg_res[1], rd, 1, MO_64);
7535
7536 tcg_temp_free_i64(tcg_op1);
7537 tcg_temp_free_i64(tcg_op2);
7538 tcg_temp_free_i64(tcg_res[0]);
7539 tcg_temp_free_i64(tcg_res[1]);
Peter Maydelle1cea112014-01-31 14:47:37 +00007540}
7541
Peter Maydell8b12a0c2014-02-08 14:46:55 +00007542/* Helper functions for 32 bit comparisons */
7543static void gen_max_s32(TCGv_i32 res, TCGv_i32 op1, TCGv_i32 op2)
7544{
7545 tcg_gen_movcond_i32(TCG_COND_GE, res, op1, op2, op1, op2);
7546}
7547
7548static void gen_max_u32(TCGv_i32 res, TCGv_i32 op1, TCGv_i32 op2)
7549{
7550 tcg_gen_movcond_i32(TCG_COND_GEU, res, op1, op2, op1, op2);
7551}
7552
7553static void gen_min_s32(TCGv_i32 res, TCGv_i32 op1, TCGv_i32 op2)
7554{
7555 tcg_gen_movcond_i32(TCG_COND_LE, res, op1, op2, op1, op2);
7556}
7557
7558static void gen_min_u32(TCGv_i32 res, TCGv_i32 op1, TCGv_i32 op2)
7559{
7560 tcg_gen_movcond_i32(TCG_COND_LEU, res, op1, op2, op1, op2);
7561}
7562
Alex Bennéebc242f92014-02-20 10:35:50 +00007563/* Pairwise op subgroup of C3.6.16.
7564 *
7565 * This is called directly or via the handle_3same_float for float pairwise
7566 * operations where the opcode and size are calculated differently.
7567 */
7568static void handle_simd_3same_pair(DisasContext *s, int is_q, int u, int opcode,
7569 int size, int rn, int rm, int rd)
Peter Maydelle1cea112014-01-31 14:47:37 +00007570{
Alex Bennéebc242f92014-02-20 10:35:50 +00007571 TCGv_ptr fpst;
Peter Maydell0173a002014-02-08 14:46:55 +00007572 int pass;
7573
Alex Bennéebc242f92014-02-20 10:35:50 +00007574 /* Floating point operations need fpst */
7575 if (opcode >= 0x58) {
7576 fpst = get_fpstatus_ptr();
7577 } else {
7578 TCGV_UNUSED_PTR(fpst);
Peter Maydell0173a002014-02-08 14:46:55 +00007579 }
7580
7581 /* These operations work on the concatenated rm:rn, with each pair of
7582 * adjacent elements being operated on to produce an element in the result.
7583 */
7584 if (size == 3) {
7585 TCGv_i64 tcg_res[2];
7586
7587 for (pass = 0; pass < 2; pass++) {
7588 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7589 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7590 int passreg = (pass == 0) ? rn : rm;
7591
7592 read_vec_element(s, tcg_op1, passreg, 0, MO_64);
7593 read_vec_element(s, tcg_op2, passreg, 1, MO_64);
7594 tcg_res[pass] = tcg_temp_new_i64();
7595
Alex Bennéebc242f92014-02-20 10:35:50 +00007596 switch (opcode) {
7597 case 0x17: /* ADDP */
7598 tcg_gen_add_i64(tcg_res[pass], tcg_op1, tcg_op2);
7599 break;
7600 case 0x58: /* FMAXNMP */
7601 gen_helper_vfp_maxnumd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7602 break;
7603 case 0x5a: /* FADDP */
7604 gen_helper_vfp_addd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7605 break;
7606 case 0x5e: /* FMAXP */
7607 gen_helper_vfp_maxd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7608 break;
7609 case 0x78: /* FMINNMP */
7610 gen_helper_vfp_minnumd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7611 break;
7612 case 0x7e: /* FMINP */
7613 gen_helper_vfp_mind(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7614 break;
7615 default:
7616 g_assert_not_reached();
7617 }
Peter Maydell0173a002014-02-08 14:46:55 +00007618
7619 tcg_temp_free_i64(tcg_op1);
7620 tcg_temp_free_i64(tcg_op2);
7621 }
7622
7623 for (pass = 0; pass < 2; pass++) {
7624 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
7625 tcg_temp_free_i64(tcg_res[pass]);
7626 }
7627 } else {
7628 int maxpass = is_q ? 4 : 2;
7629 TCGv_i32 tcg_res[4];
7630
7631 for (pass = 0; pass < maxpass; pass++) {
7632 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
7633 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
Alex Bennéebc242f92014-02-20 10:35:50 +00007634 NeonGenTwoOpFn *genfn = NULL;
Peter Maydell0173a002014-02-08 14:46:55 +00007635 int passreg = pass < (maxpass / 2) ? rn : rm;
7636 int passelt = (is_q && (pass & 1)) ? 2 : 0;
7637
7638 read_vec_element_i32(s, tcg_op1, passreg, passelt, MO_32);
7639 read_vec_element_i32(s, tcg_op2, passreg, passelt + 1, MO_32);
7640 tcg_res[pass] = tcg_temp_new_i32();
7641
7642 switch (opcode) {
7643 case 0x17: /* ADDP */
7644 {
7645 static NeonGenTwoOpFn * const fns[3] = {
7646 gen_helper_neon_padd_u8,
7647 gen_helper_neon_padd_u16,
7648 tcg_gen_add_i32,
7649 };
7650 genfn = fns[size];
7651 break;
7652 }
7653 case 0x14: /* SMAXP, UMAXP */
7654 {
7655 static NeonGenTwoOpFn * const fns[3][2] = {
7656 { gen_helper_neon_pmax_s8, gen_helper_neon_pmax_u8 },
7657 { gen_helper_neon_pmax_s16, gen_helper_neon_pmax_u16 },
7658 { gen_max_s32, gen_max_u32 },
7659 };
7660 genfn = fns[size][u];
7661 break;
7662 }
7663 case 0x15: /* SMINP, UMINP */
7664 {
7665 static NeonGenTwoOpFn * const fns[3][2] = {
7666 { gen_helper_neon_pmin_s8, gen_helper_neon_pmin_u8 },
7667 { gen_helper_neon_pmin_s16, gen_helper_neon_pmin_u16 },
7668 { gen_min_s32, gen_min_u32 },
7669 };
7670 genfn = fns[size][u];
7671 break;
7672 }
Alex Bennéebc242f92014-02-20 10:35:50 +00007673 /* The FP operations are all on single floats (32 bit) */
7674 case 0x58: /* FMAXNMP */
7675 gen_helper_vfp_maxnums(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7676 break;
7677 case 0x5a: /* FADDP */
7678 gen_helper_vfp_adds(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7679 break;
7680 case 0x5e: /* FMAXP */
7681 gen_helper_vfp_maxs(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7682 break;
7683 case 0x78: /* FMINNMP */
7684 gen_helper_vfp_minnums(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7685 break;
7686 case 0x7e: /* FMINP */
7687 gen_helper_vfp_mins(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7688 break;
Peter Maydell0173a002014-02-08 14:46:55 +00007689 default:
7690 g_assert_not_reached();
7691 }
7692
Alex Bennéebc242f92014-02-20 10:35:50 +00007693 /* FP ops called directly, otherwise call now */
7694 if (genfn) {
7695 genfn(tcg_res[pass], tcg_op1, tcg_op2);
7696 }
Peter Maydell0173a002014-02-08 14:46:55 +00007697
7698 tcg_temp_free_i32(tcg_op1);
7699 tcg_temp_free_i32(tcg_op2);
7700 }
7701
7702 for (pass = 0; pass < maxpass; pass++) {
7703 write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_32);
7704 tcg_temp_free_i32(tcg_res[pass]);
7705 }
7706 if (!is_q) {
7707 clear_vec_high(s, rd);
7708 }
7709 }
Alex Bennéebc242f92014-02-20 10:35:50 +00007710
7711 if (!TCGV_IS_UNUSED_PTR(fpst)) {
7712 tcg_temp_free_ptr(fpst);
7713 }
Peter Maydelle1cea112014-01-31 14:47:37 +00007714}
7715
7716/* Floating point op subgroup of C3.6.16. */
7717static void disas_simd_3same_float(DisasContext *s, uint32_t insn)
7718{
Peter Maydell845ea092014-01-31 14:47:37 +00007719 /* For floating point ops, the U, size[1] and opcode bits
7720 * together indicate the operation. size[0] indicates single
7721 * or double.
7722 */
7723 int fpopcode = extract32(insn, 11, 5)
7724 | (extract32(insn, 23, 1) << 5)
7725 | (extract32(insn, 29, 1) << 6);
7726 int is_q = extract32(insn, 30, 1);
7727 int size = extract32(insn, 22, 1);
7728 int rm = extract32(insn, 16, 5);
7729 int rn = extract32(insn, 5, 5);
7730 int rd = extract32(insn, 0, 5);
7731
7732 int datasize = is_q ? 128 : 64;
7733 int esize = 32 << size;
7734 int elements = datasize / esize;
7735
7736 if (size == 1 && !is_q) {
7737 unallocated_encoding(s);
7738 return;
7739 }
7740
7741 switch (fpopcode) {
7742 case 0x58: /* FMAXNMP */
7743 case 0x5a: /* FADDP */
7744 case 0x5e: /* FMAXP */
7745 case 0x78: /* FMINNMP */
7746 case 0x7e: /* FMINP */
Alex Bennéebc242f92014-02-20 10:35:50 +00007747 if (size && !is_q) {
7748 unallocated_encoding(s);
7749 return;
7750 }
7751 handle_simd_3same_pair(s, is_q, 0, fpopcode, size ? MO_64 : MO_32,
7752 rn, rm, rd);
Peter Maydell845ea092014-01-31 14:47:37 +00007753 return;
7754 case 0x1b: /* FMULX */
Peter Maydell845ea092014-01-31 14:47:37 +00007755 case 0x1f: /* FRECPS */
7756 case 0x3f: /* FRSQRTS */
Peter Maydell845ea092014-01-31 14:47:37 +00007757 case 0x5d: /* FACGE */
Peter Maydell845ea092014-01-31 14:47:37 +00007758 case 0x7d: /* FACGT */
7759 case 0x19: /* FMLA */
7760 case 0x39: /* FMLS */
Peter Maydell845ea092014-01-31 14:47:37 +00007761 case 0x18: /* FMAXNM */
7762 case 0x1a: /* FADD */
Alex Bennée8908f4d2014-02-20 10:35:49 +00007763 case 0x1c: /* FCMEQ */
Peter Maydell845ea092014-01-31 14:47:37 +00007764 case 0x1e: /* FMAX */
7765 case 0x38: /* FMINNM */
7766 case 0x3a: /* FSUB */
7767 case 0x3e: /* FMIN */
7768 case 0x5b: /* FMUL */
Alex Bennée8908f4d2014-02-20 10:35:49 +00007769 case 0x5c: /* FCMGE */
Peter Maydell845ea092014-01-31 14:47:37 +00007770 case 0x5f: /* FDIV */
7771 case 0x7a: /* FABD */
Alex Bennée8908f4d2014-02-20 10:35:49 +00007772 case 0x7c: /* FCMGT */
Peter Maydell845ea092014-01-31 14:47:37 +00007773 handle_3same_float(s, size, elements, fpopcode, rd, rn, rm);
7774 return;
7775 default:
7776 unallocated_encoding(s);
7777 return;
7778 }
Peter Maydelle1cea112014-01-31 14:47:37 +00007779}
7780
7781/* Integer op subgroup of C3.6.16. */
7782static void disas_simd_3same_int(DisasContext *s, uint32_t insn)
7783{
Peter Maydell1f8a73a2014-01-31 14:47:37 +00007784 int is_q = extract32(insn, 30, 1);
7785 int u = extract32(insn, 29, 1);
7786 int size = extract32(insn, 22, 2);
7787 int opcode = extract32(insn, 11, 5);
7788 int rm = extract32(insn, 16, 5);
7789 int rn = extract32(insn, 5, 5);
7790 int rd = extract32(insn, 0, 5);
7791 int pass;
7792
7793 switch (opcode) {
7794 case 0x13: /* MUL, PMUL */
7795 if (u && size != 0) {
7796 unallocated_encoding(s);
7797 return;
7798 }
7799 /* fall through */
7800 case 0x0: /* SHADD, UHADD */
7801 case 0x2: /* SRHADD, URHADD */
7802 case 0x4: /* SHSUB, UHSUB */
7803 case 0xc: /* SMAX, UMAX */
7804 case 0xd: /* SMIN, UMIN */
7805 case 0xe: /* SABD, UABD */
7806 case 0xf: /* SABA, UABA */
7807 case 0x12: /* MLA, MLS */
7808 if (size == 3) {
7809 unallocated_encoding(s);
7810 return;
7811 }
Peter Maydell8b12a0c2014-02-08 14:46:55 +00007812 break;
Peter Maydell1f8a73a2014-01-31 14:47:37 +00007813 case 0x16: /* SQDMULH, SQRDMULH */
7814 if (size == 0 || size == 3) {
7815 unallocated_encoding(s);
7816 return;
7817 }
Peter Maydell8b12a0c2014-02-08 14:46:55 +00007818 break;
Peter Maydell1f8a73a2014-01-31 14:47:37 +00007819 default:
7820 if (size == 3 && !is_q) {
7821 unallocated_encoding(s);
7822 return;
7823 }
7824 break;
7825 }
7826
7827 if (size == 3) {
7828 for (pass = 0; pass < (is_q ? 2 : 1); pass++) {
7829 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7830 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7831 TCGv_i64 tcg_res = tcg_temp_new_i64();
7832
7833 read_vec_element(s, tcg_op1, rn, pass, MO_64);
7834 read_vec_element(s, tcg_op2, rm, pass, MO_64);
7835
7836 handle_3same_64(s, opcode, u, tcg_res, tcg_op1, tcg_op2);
7837
7838 write_vec_element(s, tcg_res, rd, pass, MO_64);
7839
7840 tcg_temp_free_i64(tcg_res);
7841 tcg_temp_free_i64(tcg_op1);
7842 tcg_temp_free_i64(tcg_op2);
7843 }
7844 } else {
7845 for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
7846 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
7847 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
7848 TCGv_i32 tcg_res = tcg_temp_new_i32();
Peter Maydell6d9571f2014-02-08 14:46:55 +00007849 NeonGenTwoOpFn *genfn = NULL;
7850 NeonGenTwoOpEnvFn *genenvfn = NULL;
Peter Maydell1f8a73a2014-01-31 14:47:37 +00007851
7852 read_vec_element_i32(s, tcg_op1, rn, pass, MO_32);
7853 read_vec_element_i32(s, tcg_op2, rm, pass, MO_32);
7854
7855 switch (opcode) {
Peter Maydell8b12a0c2014-02-08 14:46:55 +00007856 case 0x0: /* SHADD, UHADD */
7857 {
7858 static NeonGenTwoOpFn * const fns[3][2] = {
7859 { gen_helper_neon_hadd_s8, gen_helper_neon_hadd_u8 },
7860 { gen_helper_neon_hadd_s16, gen_helper_neon_hadd_u16 },
7861 { gen_helper_neon_hadd_s32, gen_helper_neon_hadd_u32 },
7862 };
7863 genfn = fns[size][u];
7864 break;
7865 }
Peter Maydell6d9571f2014-02-08 14:46:55 +00007866 case 0x1: /* SQADD, UQADD */
7867 {
7868 static NeonGenTwoOpEnvFn * const fns[3][2] = {
7869 { gen_helper_neon_qadd_s8, gen_helper_neon_qadd_u8 },
7870 { gen_helper_neon_qadd_s16, gen_helper_neon_qadd_u16 },
7871 { gen_helper_neon_qadd_s32, gen_helper_neon_qadd_u32 },
7872 };
7873 genenvfn = fns[size][u];
7874 break;
7875 }
Peter Maydell8b12a0c2014-02-08 14:46:55 +00007876 case 0x2: /* SRHADD, URHADD */
7877 {
7878 static NeonGenTwoOpFn * const fns[3][2] = {
7879 { gen_helper_neon_rhadd_s8, gen_helper_neon_rhadd_u8 },
7880 { gen_helper_neon_rhadd_s16, gen_helper_neon_rhadd_u16 },
7881 { gen_helper_neon_rhadd_s32, gen_helper_neon_rhadd_u32 },
7882 };
7883 genfn = fns[size][u];
7884 break;
7885 }
7886 case 0x4: /* SHSUB, UHSUB */
7887 {
7888 static NeonGenTwoOpFn * const fns[3][2] = {
7889 { gen_helper_neon_hsub_s8, gen_helper_neon_hsub_u8 },
7890 { gen_helper_neon_hsub_s16, gen_helper_neon_hsub_u16 },
7891 { gen_helper_neon_hsub_s32, gen_helper_neon_hsub_u32 },
7892 };
7893 genfn = fns[size][u];
7894 break;
7895 }
Peter Maydell6d9571f2014-02-08 14:46:55 +00007896 case 0x5: /* SQSUB, UQSUB */
7897 {
7898 static NeonGenTwoOpEnvFn * const fns[3][2] = {
7899 { gen_helper_neon_qsub_s8, gen_helper_neon_qsub_u8 },
7900 { gen_helper_neon_qsub_s16, gen_helper_neon_qsub_u16 },
7901 { gen_helper_neon_qsub_s32, gen_helper_neon_qsub_u32 },
7902 };
7903 genenvfn = fns[size][u];
7904 break;
7905 }
Peter Maydell1f8a73a2014-01-31 14:47:37 +00007906 case 0x6: /* CMGT, CMHI */
7907 {
7908 static NeonGenTwoOpFn * const fns[3][2] = {
7909 { gen_helper_neon_cgt_s8, gen_helper_neon_cgt_u8 },
7910 { gen_helper_neon_cgt_s16, gen_helper_neon_cgt_u16 },
7911 { gen_helper_neon_cgt_s32, gen_helper_neon_cgt_u32 },
7912 };
7913 genfn = fns[size][u];
7914 break;
7915 }
7916 case 0x7: /* CMGE, CMHS */
7917 {
7918 static NeonGenTwoOpFn * const fns[3][2] = {
7919 { gen_helper_neon_cge_s8, gen_helper_neon_cge_u8 },
7920 { gen_helper_neon_cge_s16, gen_helper_neon_cge_u16 },
7921 { gen_helper_neon_cge_s32, gen_helper_neon_cge_u32 },
7922 };
7923 genfn = fns[size][u];
7924 break;
7925 }
Peter Maydell6d9571f2014-02-08 14:46:55 +00007926 case 0x8: /* SSHL, USHL */
7927 {
7928 static NeonGenTwoOpFn * const fns[3][2] = {
7929 { gen_helper_neon_shl_s8, gen_helper_neon_shl_u8 },
7930 { gen_helper_neon_shl_s16, gen_helper_neon_shl_u16 },
7931 { gen_helper_neon_shl_s32, gen_helper_neon_shl_u32 },
7932 };
7933 genfn = fns[size][u];
7934 break;
7935 }
7936 case 0x9: /* SQSHL, UQSHL */
7937 {
7938 static NeonGenTwoOpEnvFn * const fns[3][2] = {
7939 { gen_helper_neon_qshl_s8, gen_helper_neon_qshl_u8 },
7940 { gen_helper_neon_qshl_s16, gen_helper_neon_qshl_u16 },
7941 { gen_helper_neon_qshl_s32, gen_helper_neon_qshl_u32 },
7942 };
7943 genenvfn = fns[size][u];
7944 break;
7945 }
7946 case 0xa: /* SRSHL, URSHL */
7947 {
7948 static NeonGenTwoOpFn * const fns[3][2] = {
7949 { gen_helper_neon_rshl_s8, gen_helper_neon_rshl_u8 },
7950 { gen_helper_neon_rshl_s16, gen_helper_neon_rshl_u16 },
7951 { gen_helper_neon_rshl_s32, gen_helper_neon_rshl_u32 },
7952 };
7953 genfn = fns[size][u];
7954 break;
7955 }
7956 case 0xb: /* SQRSHL, UQRSHL */
7957 {
7958 static NeonGenTwoOpEnvFn * const fns[3][2] = {
7959 { gen_helper_neon_qrshl_s8, gen_helper_neon_qrshl_u8 },
7960 { gen_helper_neon_qrshl_s16, gen_helper_neon_qrshl_u16 },
7961 { gen_helper_neon_qrshl_s32, gen_helper_neon_qrshl_u32 },
7962 };
7963 genenvfn = fns[size][u];
7964 break;
7965 }
Peter Maydell8b12a0c2014-02-08 14:46:55 +00007966 case 0xc: /* SMAX, UMAX */
7967 {
7968 static NeonGenTwoOpFn * const fns[3][2] = {
7969 { gen_helper_neon_max_s8, gen_helper_neon_max_u8 },
7970 { gen_helper_neon_max_s16, gen_helper_neon_max_u16 },
7971 { gen_max_s32, gen_max_u32 },
7972 };
7973 genfn = fns[size][u];
7974 break;
7975 }
7976
7977 case 0xd: /* SMIN, UMIN */
7978 {
7979 static NeonGenTwoOpFn * const fns[3][2] = {
7980 { gen_helper_neon_min_s8, gen_helper_neon_min_u8 },
7981 { gen_helper_neon_min_s16, gen_helper_neon_min_u16 },
7982 { gen_min_s32, gen_min_u32 },
7983 };
7984 genfn = fns[size][u];
7985 break;
7986 }
7987 case 0xe: /* SABD, UABD */
7988 case 0xf: /* SABA, UABA */
7989 {
7990 static NeonGenTwoOpFn * const fns[3][2] = {
7991 { gen_helper_neon_abd_s8, gen_helper_neon_abd_u8 },
7992 { gen_helper_neon_abd_s16, gen_helper_neon_abd_u16 },
7993 { gen_helper_neon_abd_s32, gen_helper_neon_abd_u32 },
7994 };
7995 genfn = fns[size][u];
7996 break;
7997 }
Peter Maydell1f8a73a2014-01-31 14:47:37 +00007998 case 0x10: /* ADD, SUB */
7999 {
8000 static NeonGenTwoOpFn * const fns[3][2] = {
8001 { gen_helper_neon_add_u8, gen_helper_neon_sub_u8 },
8002 { gen_helper_neon_add_u16, gen_helper_neon_sub_u16 },
8003 { tcg_gen_add_i32, tcg_gen_sub_i32 },
8004 };
8005 genfn = fns[size][u];
8006 break;
8007 }
8008 case 0x11: /* CMTST, CMEQ */
8009 {
8010 static NeonGenTwoOpFn * const fns[3][2] = {
8011 { gen_helper_neon_tst_u8, gen_helper_neon_ceq_u8 },
8012 { gen_helper_neon_tst_u16, gen_helper_neon_ceq_u16 },
8013 { gen_helper_neon_tst_u32, gen_helper_neon_ceq_u32 },
8014 };
8015 genfn = fns[size][u];
8016 break;
8017 }
Peter Maydell8b12a0c2014-02-08 14:46:55 +00008018 case 0x13: /* MUL, PMUL */
8019 if (u) {
8020 /* PMUL */
8021 assert(size == 0);
8022 genfn = gen_helper_neon_mul_p8;
8023 break;
8024 }
8025 /* fall through : MUL */
8026 case 0x12: /* MLA, MLS */
8027 {
8028 static NeonGenTwoOpFn * const fns[3] = {
8029 gen_helper_neon_mul_u8,
8030 gen_helper_neon_mul_u16,
8031 tcg_gen_mul_i32,
8032 };
8033 genfn = fns[size];
8034 break;
8035 }
8036 case 0x16: /* SQDMULH, SQRDMULH */
8037 {
8038 static NeonGenTwoOpEnvFn * const fns[2][2] = {
8039 { gen_helper_neon_qdmulh_s16, gen_helper_neon_qrdmulh_s16 },
8040 { gen_helper_neon_qdmulh_s32, gen_helper_neon_qrdmulh_s32 },
8041 };
8042 assert(size == 1 || size == 2);
8043 genenvfn = fns[size - 1][u];
8044 break;
8045 }
Peter Maydell1f8a73a2014-01-31 14:47:37 +00008046 default:
8047 g_assert_not_reached();
8048 }
8049
Peter Maydell6d9571f2014-02-08 14:46:55 +00008050 if (genenvfn) {
8051 genenvfn(tcg_res, cpu_env, tcg_op1, tcg_op2);
8052 } else {
8053 genfn(tcg_res, tcg_op1, tcg_op2);
8054 }
Peter Maydell1f8a73a2014-01-31 14:47:37 +00008055
Peter Maydell8b12a0c2014-02-08 14:46:55 +00008056 if (opcode == 0xf || opcode == 0x12) {
8057 /* SABA, UABA, MLA, MLS: accumulating ops */
8058 static NeonGenTwoOpFn * const fns[3][2] = {
8059 { gen_helper_neon_add_u8, gen_helper_neon_sub_u8 },
8060 { gen_helper_neon_add_u16, gen_helper_neon_sub_u16 },
8061 { tcg_gen_add_i32, tcg_gen_sub_i32 },
8062 };
8063 bool is_sub = (opcode == 0x12 && u); /* MLS */
8064
8065 genfn = fns[size][is_sub];
8066 read_vec_element_i32(s, tcg_op1, rd, pass, MO_32);
8067 genfn(tcg_res, tcg_res, tcg_op1);
8068 }
8069
Peter Maydell1f8a73a2014-01-31 14:47:37 +00008070 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8071
8072 tcg_temp_free_i32(tcg_res);
8073 tcg_temp_free_i32(tcg_op1);
8074 tcg_temp_free_i32(tcg_op2);
8075 }
8076 }
8077
8078 if (!is_q) {
8079 clear_vec_high(s, rd);
8080 }
Peter Maydelle1cea112014-01-31 14:47:37 +00008081}
8082
Alex Bennée384b26f2014-01-31 14:47:30 +00008083/* C3.6.16 AdvSIMD three same
8084 * 31 30 29 28 24 23 22 21 20 16 15 11 10 9 5 4 0
8085 * +---+---+---+-----------+------+---+------+--------+---+------+------+
8086 * | 0 | Q | U | 0 1 1 1 0 | size | 1 | Rm | opcode | 1 | Rn | Rd |
8087 * +---+---+---+-----------+------+---+------+--------+---+------+------+
8088 */
8089static void disas_simd_three_reg_same(DisasContext *s, uint32_t insn)
8090{
Peter Maydelle1cea112014-01-31 14:47:37 +00008091 int opcode = extract32(insn, 11, 5);
8092
8093 switch (opcode) {
8094 case 0x3: /* logic ops */
8095 disas_simd_3same_logic(s, insn);
8096 break;
8097 case 0x17: /* ADDP */
8098 case 0x14: /* SMAXP, UMAXP */
8099 case 0x15: /* SMINP, UMINP */
Alex Bennéebc242f92014-02-20 10:35:50 +00008100 {
Peter Maydelle1cea112014-01-31 14:47:37 +00008101 /* Pairwise operations */
Alex Bennéebc242f92014-02-20 10:35:50 +00008102 int is_q = extract32(insn, 30, 1);
8103 int u = extract32(insn, 29, 1);
8104 int size = extract32(insn, 22, 2);
8105 int rm = extract32(insn, 16, 5);
8106 int rn = extract32(insn, 5, 5);
8107 int rd = extract32(insn, 0, 5);
8108 if (opcode == 0x17) {
8109 if (u || (size == 3 && !is_q)) {
8110 unallocated_encoding(s);
8111 return;
8112 }
8113 } else {
8114 if (size == 3) {
8115 unallocated_encoding(s);
8116 return;
8117 }
8118 }
8119 handle_simd_3same_pair(s, is_q, u, opcode, size, rn, rm, rd);
Peter Maydelle1cea112014-01-31 14:47:37 +00008120 break;
Alex Bennéebc242f92014-02-20 10:35:50 +00008121 }
Peter Maydelle1cea112014-01-31 14:47:37 +00008122 case 0x18 ... 0x31:
8123 /* floating point ops, sz[1] and U are part of opcode */
8124 disas_simd_3same_float(s, insn);
8125 break;
8126 default:
8127 disas_simd_3same_int(s, insn);
8128 break;
8129 }
Alex Bennée384b26f2014-01-31 14:47:30 +00008130}
8131
Peter Maydelld980fd52014-02-03 23:31:52 +00008132static void handle_2misc_narrow(DisasContext *s, int opcode, bool u, bool is_q,
8133 int size, int rn, int rd)
8134{
8135 /* Handle 2-reg-misc ops which are narrowing (so each 2*size element
8136 * in the source becomes a size element in the destination).
8137 */
8138 int pass;
8139 TCGv_i32 tcg_res[2];
8140 int destelt = is_q ? 2 : 0;
8141
8142 for (pass = 0; pass < 2; pass++) {
8143 TCGv_i64 tcg_op = tcg_temp_new_i64();
8144 NeonGenNarrowFn *genfn = NULL;
8145 NeonGenNarrowEnvFn *genenvfn = NULL;
8146
8147 read_vec_element(s, tcg_op, rn, pass, MO_64);
8148 tcg_res[pass] = tcg_temp_new_i32();
8149
8150 switch (opcode) {
8151 case 0x12: /* XTN, SQXTUN */
8152 {
8153 static NeonGenNarrowFn * const xtnfns[3] = {
8154 gen_helper_neon_narrow_u8,
8155 gen_helper_neon_narrow_u16,
8156 tcg_gen_trunc_i64_i32,
8157 };
8158 static NeonGenNarrowEnvFn * const sqxtunfns[3] = {
8159 gen_helper_neon_unarrow_sat8,
8160 gen_helper_neon_unarrow_sat16,
8161 gen_helper_neon_unarrow_sat32,
8162 };
8163 if (u) {
8164 genenvfn = sqxtunfns[size];
8165 } else {
8166 genfn = xtnfns[size];
8167 }
8168 break;
8169 }
8170 case 0x14: /* SQXTN, UQXTN */
8171 {
8172 static NeonGenNarrowEnvFn * const fns[3][2] = {
8173 { gen_helper_neon_narrow_sat_s8,
8174 gen_helper_neon_narrow_sat_u8 },
8175 { gen_helper_neon_narrow_sat_s16,
8176 gen_helper_neon_narrow_sat_u16 },
8177 { gen_helper_neon_narrow_sat_s32,
8178 gen_helper_neon_narrow_sat_u32 },
8179 };
8180 genenvfn = fns[size][u];
8181 break;
8182 }
8183 default:
8184 g_assert_not_reached();
8185 }
8186
8187 if (genfn) {
8188 genfn(tcg_res[pass], tcg_op);
8189 } else {
8190 genenvfn(tcg_res[pass], cpu_env, tcg_op);
8191 }
8192
8193 tcg_temp_free_i64(tcg_op);
8194 }
8195
8196 for (pass = 0; pass < 2; pass++) {
8197 write_vec_element_i32(s, tcg_res[pass], rd, destelt + pass, MO_32);
8198 tcg_temp_free_i32(tcg_res[pass]);
8199 }
8200 if (!is_q) {
8201 clear_vec_high(s, rd);
8202 }
8203}
8204
Alex Bennée39d82112014-02-03 23:31:52 +00008205static void handle_rev(DisasContext *s, int opcode, bool u,
8206 bool is_q, int size, int rn, int rd)
8207{
8208 int op = (opcode << 1) | u;
8209 int opsz = op + size;
8210 int grp_size = 3 - opsz;
8211 int dsize = is_q ? 128 : 64;
8212 int i;
8213
8214 if (opsz >= 3) {
8215 unallocated_encoding(s);
8216 return;
8217 }
8218
8219 if (size == 0) {
8220 /* Special case bytes, use bswap op on each group of elements */
8221 int groups = dsize / (8 << grp_size);
8222
8223 for (i = 0; i < groups; i++) {
8224 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
8225
8226 read_vec_element(s, tcg_tmp, rn, i, grp_size);
8227 switch (grp_size) {
8228 case MO_16:
8229 tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
8230 break;
8231 case MO_32:
8232 tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp);
8233 break;
8234 case MO_64:
8235 tcg_gen_bswap64_i64(tcg_tmp, tcg_tmp);
8236 break;
8237 default:
8238 g_assert_not_reached();
8239 }
8240 write_vec_element(s, tcg_tmp, rd, i, grp_size);
8241 tcg_temp_free_i64(tcg_tmp);
8242 }
8243 if (!is_q) {
8244 clear_vec_high(s, rd);
8245 }
8246 } else {
8247 int revmask = (1 << grp_size) - 1;
8248 int esize = 8 << size;
8249 int elements = dsize / esize;
8250 TCGv_i64 tcg_rn = tcg_temp_new_i64();
8251 TCGv_i64 tcg_rd = tcg_const_i64(0);
8252 TCGv_i64 tcg_rd_hi = tcg_const_i64(0);
8253
8254 for (i = 0; i < elements; i++) {
8255 int e_rev = (i & 0xf) ^ revmask;
8256 int off = e_rev * esize;
8257 read_vec_element(s, tcg_rn, rn, i, size);
8258 if (off >= 64) {
8259 tcg_gen_deposit_i64(tcg_rd_hi, tcg_rd_hi,
8260 tcg_rn, off - 64, esize);
8261 } else {
8262 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, off, esize);
8263 }
8264 }
8265 write_vec_element(s, tcg_rd, rd, 0, MO_64);
8266 write_vec_element(s, tcg_rd_hi, rd, 1, MO_64);
8267
8268 tcg_temp_free_i64(tcg_rd_hi);
8269 tcg_temp_free_i64(tcg_rd);
8270 tcg_temp_free_i64(tcg_rn);
8271 }
8272}
8273
Alex Bennée384b26f2014-01-31 14:47:30 +00008274/* C3.6.17 AdvSIMD two reg misc
8275 * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
8276 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
8277 * | 0 | Q | U | 0 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 | Rn | Rd |
8278 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
8279 */
8280static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
8281{
Peter Maydell45aecc62014-02-08 14:46:56 +00008282 int size = extract32(insn, 22, 2);
8283 int opcode = extract32(insn, 12, 5);
8284 bool u = extract32(insn, 29, 1);
8285 bool is_q = extract32(insn, 30, 1);
Peter Maydell94b6c912014-02-03 23:31:51 +00008286 int rn = extract32(insn, 5, 5);
8287 int rd = extract32(insn, 0, 5);
Peter Maydell45aecc62014-02-08 14:46:56 +00008288
8289 switch (opcode) {
8290 case 0x0: /* REV64, REV32 */
8291 case 0x1: /* REV16 */
Alex Bennée39d82112014-02-03 23:31:52 +00008292 handle_rev(s, opcode, u, is_q, size, rn, rd);
Peter Maydell45aecc62014-02-08 14:46:56 +00008293 return;
Peter Maydell86cbc412014-02-03 23:31:51 +00008294 case 0x5: /* CNT, NOT, RBIT */
8295 if (u && size == 0) {
8296 /* NOT: adjust size so we can use the 64-bits-at-a-time loop. */
8297 size = 3;
8298 break;
8299 } else if (u && size == 1) {
8300 /* RBIT */
8301 break;
8302 } else if (!u && size == 0) {
8303 /* CNT */
8304 break;
Peter Maydell45aecc62014-02-08 14:46:56 +00008305 }
Peter Maydell86cbc412014-02-03 23:31:51 +00008306 unallocated_encoding(s);
Peter Maydell45aecc62014-02-08 14:46:56 +00008307 return;
Peter Maydelld980fd52014-02-03 23:31:52 +00008308 case 0x12: /* XTN, XTN2, SQXTUN, SQXTUN2 */
8309 case 0x14: /* SQXTN, SQXTN2, UQXTN, UQXTN2 */
8310 if (size == 3) {
8311 unallocated_encoding(s);
8312 return;
8313 }
8314 handle_2misc_narrow(s, opcode, u, is_q, size, rn, rd);
8315 return;
Peter Maydell45aecc62014-02-08 14:46:56 +00008316 case 0x2: /* SADDLP, UADDLP */
8317 case 0x4: /* CLS, CLZ */
8318 case 0x6: /* SADALP, UADALP */
Peter Maydell45aecc62014-02-08 14:46:56 +00008319 if (size == 3) {
8320 unallocated_encoding(s);
8321 return;
8322 }
8323 unsupported_encoding(s, insn);
8324 return;
8325 case 0x13: /* SHLL, SHLL2 */
8326 if (u == 0 || size == 3) {
8327 unallocated_encoding(s);
8328 return;
8329 }
8330 unsupported_encoding(s, insn);
8331 return;
8332 case 0xa: /* CMLT */
8333 if (u == 1) {
8334 unallocated_encoding(s);
8335 return;
8336 }
8337 /* fall through */
Peter Maydell45aecc62014-02-08 14:46:56 +00008338 case 0x8: /* CMGT, CMGE */
8339 case 0x9: /* CMEQ, CMLE */
8340 case 0xb: /* ABS, NEG */
8341 if (size == 3 && !is_q) {
8342 unallocated_encoding(s);
8343 return;
8344 }
Peter Maydell94b6c912014-02-03 23:31:51 +00008345 break;
8346 case 0x3: /* SUQADD, USQADD */
8347 case 0x7: /* SQABS, SQNEG */
8348 if (size == 3 && !is_q) {
8349 unallocated_encoding(s);
8350 return;
8351 }
Peter Maydell45aecc62014-02-08 14:46:56 +00008352 unsupported_encoding(s, insn);
8353 return;
8354 case 0xc ... 0xf:
8355 case 0x16 ... 0x1d:
8356 case 0x1f:
8357 {
8358 /* Floating point: U, size[1] and opcode indicate operation;
8359 * size[0] indicates single or double precision.
8360 */
Peter Maydell745849b2014-03-08 20:40:20 +00008361 int is_double = extract32(size, 0, 1);
Peter Maydell45aecc62014-02-08 14:46:56 +00008362 opcode |= (extract32(size, 1, 1) << 5) | (u << 6);
Peter Maydell745849b2014-03-08 20:40:20 +00008363 size = is_double ? 3 : 2;
Peter Maydell45aecc62014-02-08 14:46:56 +00008364 switch (opcode) {
Peter Maydellf93d0132014-02-03 23:31:52 +00008365 case 0x2f: /* FABS */
8366 case 0x6f: /* FNEG */
8367 if (size == 3 && !is_q) {
8368 unallocated_encoding(s);
8369 return;
8370 }
8371 break;
Peter Maydell745849b2014-03-08 20:40:20 +00008372 case 0x1d: /* SCVTF */
8373 case 0x5d: /* UCVTF */
8374 {
8375 bool is_signed = (opcode == 0x1d) ? true : false;
8376 int elements = is_double ? 2 : is_q ? 4 : 2;
8377 if (is_double && !is_q) {
8378 unallocated_encoding(s);
8379 return;
8380 }
8381 handle_simd_intfp_conv(s, rd, rn, elements, is_signed, 0, size);
8382 return;
8383 }
Alex Bennée8908f4d2014-02-20 10:35:49 +00008384 case 0x2c: /* FCMGT (zero) */
8385 case 0x2d: /* FCMEQ (zero) */
8386 case 0x2e: /* FCMLT (zero) */
8387 case 0x6c: /* FCMGE (zero) */
8388 case 0x6d: /* FCMLE (zero) */
8389 if (size == 3 && !is_q) {
8390 unallocated_encoding(s);
8391 return;
8392 }
8393 handle_2misc_fcmp_zero(s, opcode, false, u, is_q, size, rn, rd);
8394 return;
Peter Maydell45aecc62014-02-08 14:46:56 +00008395 case 0x16: /* FCVTN, FCVTN2 */
8396 case 0x17: /* FCVTL, FCVTL2 */
8397 case 0x18: /* FRINTN */
8398 case 0x19: /* FRINTM */
8399 case 0x1a: /* FCVTNS */
8400 case 0x1b: /* FCVTMS */
8401 case 0x1c: /* FCVTAS */
Peter Maydell45aecc62014-02-08 14:46:56 +00008402 case 0x38: /* FRINTP */
8403 case 0x39: /* FRINTZ */
8404 case 0x3a: /* FCVTPS */
8405 case 0x3b: /* FCVTZS */
8406 case 0x3c: /* URECPE */
8407 case 0x3d: /* FRECPE */
8408 case 0x56: /* FCVTXN, FCVTXN2 */
8409 case 0x58: /* FRINTA */
8410 case 0x59: /* FRINTX */
8411 case 0x5a: /* FCVTNU */
8412 case 0x5b: /* FCVTMU */
8413 case 0x5c: /* FCVTAU */
Peter Maydell45aecc62014-02-08 14:46:56 +00008414 case 0x79: /* FRINTI */
8415 case 0x7a: /* FCVTPU */
8416 case 0x7b: /* FCVTZU */
8417 case 0x7c: /* URSQRTE */
8418 case 0x7d: /* FRSQRTE */
8419 case 0x7f: /* FSQRT */
8420 unsupported_encoding(s, insn);
8421 return;
8422 default:
8423 unallocated_encoding(s);
8424 return;
8425 }
8426 break;
8427 }
8428 default:
8429 unallocated_encoding(s);
8430 return;
8431 }
Peter Maydell94b6c912014-02-03 23:31:51 +00008432
8433 if (size == 3) {
8434 /* All 64-bit element operations can be shared with scalar 2misc */
8435 int pass;
8436
8437 for (pass = 0; pass < (is_q ? 2 : 1); pass++) {
8438 TCGv_i64 tcg_op = tcg_temp_new_i64();
8439 TCGv_i64 tcg_res = tcg_temp_new_i64();
8440
8441 read_vec_element(s, tcg_op, rn, pass, MO_64);
8442
8443 handle_2misc_64(s, opcode, u, tcg_res, tcg_op);
8444
8445 write_vec_element(s, tcg_res, rd, pass, MO_64);
8446
8447 tcg_temp_free_i64(tcg_res);
8448 tcg_temp_free_i64(tcg_op);
8449 }
8450 } else {
8451 int pass;
8452
8453 for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
8454 TCGv_i32 tcg_op = tcg_temp_new_i32();
8455 TCGv_i32 tcg_res = tcg_temp_new_i32();
8456 TCGCond cond;
8457
8458 read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
8459
8460 if (size == 2) {
8461 /* Special cases for 32 bit elements */
8462 switch (opcode) {
8463 case 0xa: /* CMLT */
8464 /* 32 bit integer comparison against zero, result is
8465 * test ? (2^32 - 1) : 0. We implement via setcond(test)
8466 * and inverting.
8467 */
8468 cond = TCG_COND_LT;
8469 do_cmop:
8470 tcg_gen_setcondi_i32(cond, tcg_res, tcg_op, 0);
8471 tcg_gen_neg_i32(tcg_res, tcg_res);
8472 break;
8473 case 0x8: /* CMGT, CMGE */
8474 cond = u ? TCG_COND_GE : TCG_COND_GT;
8475 goto do_cmop;
8476 case 0x9: /* CMEQ, CMLE */
8477 cond = u ? TCG_COND_LE : TCG_COND_EQ;
8478 goto do_cmop;
8479 case 0xb: /* ABS, NEG */
8480 if (u) {
8481 tcg_gen_neg_i32(tcg_res, tcg_op);
8482 } else {
8483 TCGv_i32 tcg_zero = tcg_const_i32(0);
8484 tcg_gen_neg_i32(tcg_res, tcg_op);
8485 tcg_gen_movcond_i32(TCG_COND_GT, tcg_res, tcg_op,
8486 tcg_zero, tcg_op, tcg_res);
8487 tcg_temp_free_i32(tcg_zero);
8488 }
8489 break;
Peter Maydellf93d0132014-02-03 23:31:52 +00008490 case 0x2f: /* FABS */
8491 gen_helper_vfp_abss(tcg_res, tcg_op);
8492 break;
8493 case 0x6f: /* FNEG */
8494 gen_helper_vfp_negs(tcg_res, tcg_op);
8495 break;
Peter Maydell94b6c912014-02-03 23:31:51 +00008496 default:
8497 g_assert_not_reached();
8498 }
8499 } else {
8500 /* Use helpers for 8 and 16 bit elements */
8501 switch (opcode) {
Peter Maydell86cbc412014-02-03 23:31:51 +00008502 case 0x5: /* CNT, RBIT */
8503 /* For these two insns size is part of the opcode specifier
8504 * (handled earlier); they always operate on byte elements.
8505 */
8506 if (u) {
8507 gen_helper_neon_rbit_u8(tcg_res, tcg_op);
8508 } else {
8509 gen_helper_neon_cnt_u8(tcg_res, tcg_op);
8510 }
8511 break;
Peter Maydell94b6c912014-02-03 23:31:51 +00008512 case 0x8: /* CMGT, CMGE */
8513 case 0x9: /* CMEQ, CMLE */
8514 case 0xa: /* CMLT */
8515 {
8516 static NeonGenTwoOpFn * const fns[3][2] = {
8517 { gen_helper_neon_cgt_s8, gen_helper_neon_cgt_s16 },
8518 { gen_helper_neon_cge_s8, gen_helper_neon_cge_s16 },
8519 { gen_helper_neon_ceq_u8, gen_helper_neon_ceq_u16 },
8520 };
8521 NeonGenTwoOpFn *genfn;
8522 int comp;
8523 bool reverse;
8524 TCGv_i32 tcg_zero = tcg_const_i32(0);
8525
8526 /* comp = index into [CMGT, CMGE, CMEQ, CMLE, CMLT] */
8527 comp = (opcode - 0x8) * 2 + u;
8528 /* ...but LE, LT are implemented as reverse GE, GT */
8529 reverse = (comp > 2);
8530 if (reverse) {
8531 comp = 4 - comp;
8532 }
8533 genfn = fns[comp][size];
8534 if (reverse) {
8535 genfn(tcg_res, tcg_zero, tcg_op);
8536 } else {
8537 genfn(tcg_res, tcg_op, tcg_zero);
8538 }
8539 tcg_temp_free_i32(tcg_zero);
8540 break;
8541 }
8542 case 0xb: /* ABS, NEG */
8543 if (u) {
8544 TCGv_i32 tcg_zero = tcg_const_i32(0);
8545 if (size) {
8546 gen_helper_neon_sub_u16(tcg_res, tcg_zero, tcg_op);
8547 } else {
8548 gen_helper_neon_sub_u8(tcg_res, tcg_zero, tcg_op);
8549 }
8550 tcg_temp_free_i32(tcg_zero);
8551 } else {
8552 if (size) {
8553 gen_helper_neon_abs_s16(tcg_res, tcg_op);
8554 } else {
8555 gen_helper_neon_abs_s8(tcg_res, tcg_op);
8556 }
8557 }
8558 break;
8559 default:
8560 g_assert_not_reached();
8561 }
8562 }
8563
8564 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8565
8566 tcg_temp_free_i32(tcg_res);
8567 tcg_temp_free_i32(tcg_op);
8568 }
8569 }
8570 if (!is_q) {
8571 clear_vec_high(s, rd);
8572 }
Alex Bennée384b26f2014-01-31 14:47:30 +00008573}
8574
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008575/* C3.6.13 AdvSIMD scalar x indexed element
8576 * 31 30 29 28 24 23 22 21 20 19 16 15 12 11 10 9 5 4 0
8577 * +-----+---+-----------+------+---+---+------+-----+---+---+------+------+
8578 * | 0 1 | U | 1 1 1 1 1 | size | L | M | Rm | opc | H | 0 | Rn | Rd |
8579 * +-----+---+-----------+------+---+---+------+-----+---+---+------+------+
8580 * C3.6.18 AdvSIMD vector x indexed element
Alex Bennée384b26f2014-01-31 14:47:30 +00008581 * 31 30 29 28 24 23 22 21 20 19 16 15 12 11 10 9 5 4 0
8582 * +---+---+---+-----------+------+---+---+------+-----+---+---+------+------+
8583 * | 0 | Q | U | 0 1 1 1 1 | size | L | M | Rm | opc | H | 0 | Rn | Rd |
8584 * +---+---+---+-----------+------+---+---+------+-----+---+---+------+------+
8585 */
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008586static void disas_simd_indexed(DisasContext *s, uint32_t insn)
Alex Bennée384b26f2014-01-31 14:47:30 +00008587{
Peter Maydellf5e51e72014-02-20 10:35:48 +00008588 /* This encoding has two kinds of instruction:
8589 * normal, where we perform elt x idxelt => elt for each
8590 * element in the vector
8591 * long, where we perform elt x idxelt and generate a result of
8592 * double the width of the input element
8593 * The long ops have a 'part' specifier (ie come in INSN, INSN2 pairs).
8594 */
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008595 bool is_scalar = extract32(insn, 28, 1);
Peter Maydellf5e51e72014-02-20 10:35:48 +00008596 bool is_q = extract32(insn, 30, 1);
8597 bool u = extract32(insn, 29, 1);
8598 int size = extract32(insn, 22, 2);
8599 int l = extract32(insn, 21, 1);
8600 int m = extract32(insn, 20, 1);
8601 /* Note that the Rm field here is only 4 bits, not 5 as it usually is */
8602 int rm = extract32(insn, 16, 4);
8603 int opcode = extract32(insn, 12, 4);
8604 int h = extract32(insn, 11, 1);
8605 int rn = extract32(insn, 5, 5);
8606 int rd = extract32(insn, 0, 5);
8607 bool is_long = false;
8608 bool is_fp = false;
8609 int index;
8610 TCGv_ptr fpst;
8611
8612 switch (opcode) {
8613 case 0x0: /* MLA */
8614 case 0x4: /* MLS */
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008615 if (!u || is_scalar) {
Peter Maydellf5e51e72014-02-20 10:35:48 +00008616 unallocated_encoding(s);
8617 return;
8618 }
8619 break;
8620 case 0x2: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
8621 case 0x6: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
8622 case 0xa: /* SMULL, SMULL2, UMULL, UMULL2 */
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008623 if (is_scalar) {
8624 unallocated_encoding(s);
8625 return;
8626 }
Peter Maydellf5e51e72014-02-20 10:35:48 +00008627 is_long = true;
8628 break;
8629 case 0x3: /* SQDMLAL, SQDMLAL2 */
8630 case 0x7: /* SQDMLSL, SQDMLSL2 */
8631 case 0xb: /* SQDMULL, SQDMULL2 */
8632 is_long = true;
8633 /* fall through */
8634 case 0xc: /* SQDMULH */
8635 case 0xd: /* SQRDMULH */
Peter Maydellf5e51e72014-02-20 10:35:48 +00008636 if (u) {
8637 unallocated_encoding(s);
8638 return;
8639 }
8640 break;
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008641 case 0x8: /* MUL */
8642 if (u || is_scalar) {
8643 unallocated_encoding(s);
8644 return;
8645 }
8646 break;
Peter Maydellf5e51e72014-02-20 10:35:48 +00008647 case 0x1: /* FMLA */
8648 case 0x5: /* FMLS */
8649 if (u) {
8650 unallocated_encoding(s);
8651 return;
8652 }
8653 /* fall through */
8654 case 0x9: /* FMUL, FMULX */
8655 if (!extract32(size, 1, 1)) {
8656 unallocated_encoding(s);
8657 return;
8658 }
8659 is_fp = true;
8660 break;
8661 default:
8662 unallocated_encoding(s);
8663 return;
8664 }
8665
8666 if (is_fp) {
8667 /* low bit of size indicates single/double */
8668 size = extract32(size, 0, 1) ? 3 : 2;
8669 if (size == 2) {
8670 index = h << 1 | l;
8671 } else {
8672 if (l || !is_q) {
8673 unallocated_encoding(s);
8674 return;
8675 }
8676 index = h;
8677 }
8678 rm |= (m << 4);
8679 } else {
8680 switch (size) {
8681 case 1:
8682 index = h << 2 | l << 1 | m;
8683 break;
8684 case 2:
8685 index = h << 1 | l;
8686 rm |= (m << 4);
8687 break;
8688 default:
8689 unallocated_encoding(s);
8690 return;
8691 }
8692 }
8693
Peter Maydellf5e51e72014-02-20 10:35:48 +00008694 if (is_fp) {
8695 fpst = get_fpstatus_ptr();
8696 } else {
8697 TCGV_UNUSED_PTR(fpst);
8698 }
8699
8700 if (size == 3) {
8701 TCGv_i64 tcg_idx = tcg_temp_new_i64();
8702 int pass;
8703
8704 assert(is_fp && is_q && !is_long);
8705
8706 read_vec_element(s, tcg_idx, rm, index, MO_64);
8707
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008708 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
Peter Maydellf5e51e72014-02-20 10:35:48 +00008709 TCGv_i64 tcg_op = tcg_temp_new_i64();
8710 TCGv_i64 tcg_res = tcg_temp_new_i64();
8711
8712 read_vec_element(s, tcg_op, rn, pass, MO_64);
8713
8714 switch (opcode) {
8715 case 0x5: /* FMLS */
8716 /* As usual for ARM, separate negation for fused multiply-add */
8717 gen_helper_vfp_negd(tcg_op, tcg_op);
8718 /* fall through */
8719 case 0x1: /* FMLA */
8720 read_vec_element(s, tcg_res, rd, pass, MO_64);
8721 gen_helper_vfp_muladdd(tcg_res, tcg_op, tcg_idx, tcg_res, fpst);
8722 break;
8723 case 0x9: /* FMUL, FMULX */
8724 if (u) {
8725 gen_helper_vfp_mulxd(tcg_res, tcg_op, tcg_idx, fpst);
8726 } else {
8727 gen_helper_vfp_muld(tcg_res, tcg_op, tcg_idx, fpst);
8728 }
8729 break;
8730 default:
8731 g_assert_not_reached();
8732 }
8733
8734 write_vec_element(s, tcg_res, rd, pass, MO_64);
8735 tcg_temp_free_i64(tcg_op);
8736 tcg_temp_free_i64(tcg_res);
8737 }
8738
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008739 if (is_scalar) {
8740 clear_vec_high(s, rd);
8741 }
8742
Peter Maydellf5e51e72014-02-20 10:35:48 +00008743 tcg_temp_free_i64(tcg_idx);
8744 } else if (!is_long) {
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008745 /* 32 bit floating point, or 16 or 32 bit integer.
8746 * For the 16 bit scalar case we use the usual Neon helpers and
8747 * rely on the fact that 0 op 0 == 0 with no side effects.
8748 */
Peter Maydellf5e51e72014-02-20 10:35:48 +00008749 TCGv_i32 tcg_idx = tcg_temp_new_i32();
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008750 int pass, maxpasses;
8751
8752 if (is_scalar) {
8753 maxpasses = 1;
8754 } else {
8755 maxpasses = is_q ? 4 : 2;
8756 }
Peter Maydellf5e51e72014-02-20 10:35:48 +00008757
8758 read_vec_element_i32(s, tcg_idx, rm, index, size);
8759
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008760 if (size == 1 && !is_scalar) {
Peter Maydellf5e51e72014-02-20 10:35:48 +00008761 /* The simplest way to handle the 16x16 indexed ops is to duplicate
8762 * the index into both halves of the 32 bit tcg_idx and then use
8763 * the usual Neon helpers.
8764 */
8765 tcg_gen_deposit_i32(tcg_idx, tcg_idx, tcg_idx, 16, 16);
8766 }
8767
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008768 for (pass = 0; pass < maxpasses; pass++) {
Peter Maydellf5e51e72014-02-20 10:35:48 +00008769 TCGv_i32 tcg_op = tcg_temp_new_i32();
8770 TCGv_i32 tcg_res = tcg_temp_new_i32();
8771
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008772 read_vec_element_i32(s, tcg_op, rn, pass, is_scalar ? size : MO_32);
Peter Maydellf5e51e72014-02-20 10:35:48 +00008773
8774 switch (opcode) {
8775 case 0x0: /* MLA */
8776 case 0x4: /* MLS */
8777 case 0x8: /* MUL */
8778 {
8779 static NeonGenTwoOpFn * const fns[2][2] = {
8780 { gen_helper_neon_add_u16, gen_helper_neon_sub_u16 },
8781 { tcg_gen_add_i32, tcg_gen_sub_i32 },
8782 };
8783 NeonGenTwoOpFn *genfn;
8784 bool is_sub = opcode == 0x4;
8785
8786 if (size == 1) {
8787 gen_helper_neon_mul_u16(tcg_res, tcg_op, tcg_idx);
8788 } else {
8789 tcg_gen_mul_i32(tcg_res, tcg_op, tcg_idx);
8790 }
8791 if (opcode == 0x8) {
8792 break;
8793 }
8794 read_vec_element_i32(s, tcg_op, rd, pass, MO_32);
8795 genfn = fns[size - 1][is_sub];
8796 genfn(tcg_res, tcg_op, tcg_res);
8797 break;
8798 }
8799 case 0x5: /* FMLS */
8800 /* As usual for ARM, separate negation for fused multiply-add */
8801 gen_helper_vfp_negs(tcg_op, tcg_op);
8802 /* fall through */
8803 case 0x1: /* FMLA */
8804 read_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8805 gen_helper_vfp_muladds(tcg_res, tcg_op, tcg_idx, tcg_res, fpst);
8806 break;
8807 case 0x9: /* FMUL, FMULX */
8808 if (u) {
8809 gen_helper_vfp_mulxs(tcg_res, tcg_op, tcg_idx, fpst);
8810 } else {
8811 gen_helper_vfp_muls(tcg_res, tcg_op, tcg_idx, fpst);
8812 }
8813 break;
8814 case 0xc: /* SQDMULH */
8815 if (size == 1) {
8816 gen_helper_neon_qdmulh_s16(tcg_res, cpu_env,
8817 tcg_op, tcg_idx);
8818 } else {
8819 gen_helper_neon_qdmulh_s32(tcg_res, cpu_env,
8820 tcg_op, tcg_idx);
8821 }
8822 break;
8823 case 0xd: /* SQRDMULH */
8824 if (size == 1) {
8825 gen_helper_neon_qrdmulh_s16(tcg_res, cpu_env,
8826 tcg_op, tcg_idx);
8827 } else {
8828 gen_helper_neon_qrdmulh_s32(tcg_res, cpu_env,
8829 tcg_op, tcg_idx);
8830 }
8831 break;
8832 default:
8833 g_assert_not_reached();
8834 }
8835
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008836 if (is_scalar) {
8837 write_fp_sreg(s, rd, tcg_res);
8838 } else {
8839 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8840 }
8841
Peter Maydellf5e51e72014-02-20 10:35:48 +00008842 tcg_temp_free_i32(tcg_op);
8843 tcg_temp_free_i32(tcg_res);
8844 }
8845
8846 tcg_temp_free_i32(tcg_idx);
8847
8848 if (!is_q) {
8849 clear_vec_high(s, rd);
8850 }
8851 } else {
8852 /* long ops: 16x16->32 or 32x32->64 */
Peter Maydellc44ad1f2014-02-20 10:35:49 +00008853 TCGv_i64 tcg_res[2];
8854 int pass;
8855 bool satop = extract32(opcode, 0, 1);
8856 TCGMemOp memop = MO_32;
8857
8858 if (satop || !u) {
8859 memop |= MO_SIGN;
8860 }
8861
8862 if (size == 2) {
8863 TCGv_i64 tcg_idx = tcg_temp_new_i64();
8864
8865 read_vec_element(s, tcg_idx, rm, index, memop);
8866
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008867 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
Peter Maydellc44ad1f2014-02-20 10:35:49 +00008868 TCGv_i64 tcg_op = tcg_temp_new_i64();
8869 TCGv_i64 tcg_passres;
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008870 int passelt;
Peter Maydellc44ad1f2014-02-20 10:35:49 +00008871
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008872 if (is_scalar) {
8873 passelt = 0;
8874 } else {
8875 passelt = pass + (is_q * 2);
8876 }
8877
8878 read_vec_element(s, tcg_op, rn, passelt, memop);
Peter Maydellc44ad1f2014-02-20 10:35:49 +00008879
8880 tcg_res[pass] = tcg_temp_new_i64();
8881
8882 if (opcode == 0xa || opcode == 0xb) {
8883 /* Non-accumulating ops */
8884 tcg_passres = tcg_res[pass];
8885 } else {
8886 tcg_passres = tcg_temp_new_i64();
8887 }
8888
8889 tcg_gen_mul_i64(tcg_passres, tcg_op, tcg_idx);
8890 tcg_temp_free_i64(tcg_op);
8891
8892 if (satop) {
8893 /* saturating, doubling */
8894 gen_helper_neon_addl_saturate_s64(tcg_passres, cpu_env,
8895 tcg_passres, tcg_passres);
8896 }
8897
8898 if (opcode == 0xa || opcode == 0xb) {
8899 continue;
8900 }
8901
8902 /* Accumulating op: handle accumulate step */
8903 read_vec_element(s, tcg_res[pass], rd, pass, MO_64);
8904
8905 switch (opcode) {
8906 case 0x2: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
8907 tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
8908 break;
8909 case 0x6: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
8910 tcg_gen_sub_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
8911 break;
8912 case 0x7: /* SQDMLSL, SQDMLSL2 */
8913 tcg_gen_neg_i64(tcg_passres, tcg_passres);
8914 /* fall through */
8915 case 0x3: /* SQDMLAL, SQDMLAL2 */
8916 gen_helper_neon_addl_saturate_s64(tcg_res[pass], cpu_env,
8917 tcg_res[pass],
8918 tcg_passres);
8919 break;
8920 default:
8921 g_assert_not_reached();
8922 }
8923 tcg_temp_free_i64(tcg_passres);
8924 }
8925 tcg_temp_free_i64(tcg_idx);
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008926
8927 if (is_scalar) {
8928 clear_vec_high(s, rd);
8929 }
Peter Maydellc44ad1f2014-02-20 10:35:49 +00008930 } else {
8931 TCGv_i32 tcg_idx = tcg_temp_new_i32();
8932
8933 assert(size == 1);
8934 read_vec_element_i32(s, tcg_idx, rm, index, size);
8935
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008936 if (!is_scalar) {
8937 /* The simplest way to handle the 16x16 indexed ops is to
8938 * duplicate the index into both halves of the 32 bit tcg_idx
8939 * and then use the usual Neon helpers.
8940 */
8941 tcg_gen_deposit_i32(tcg_idx, tcg_idx, tcg_idx, 16, 16);
8942 }
Peter Maydellc44ad1f2014-02-20 10:35:49 +00008943
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008944 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
Peter Maydellc44ad1f2014-02-20 10:35:49 +00008945 TCGv_i32 tcg_op = tcg_temp_new_i32();
8946 TCGv_i64 tcg_passres;
8947
Peter Maydell9f82e0f2014-02-20 10:35:49 +00008948 if (is_scalar) {
8949 read_vec_element_i32(s, tcg_op, rn, pass, size);
8950 } else {
8951 read_vec_element_i32(s, tcg_op, rn,
8952 pass + (is_q * 2), MO_32);
8953 }
8954
Peter Maydellc44ad1f2014-02-20 10:35:49 +00008955 tcg_res[pass] = tcg_temp_new_i64();
8956
8957 if (opcode == 0xa || opcode == 0xb) {
8958 /* Non-accumulating ops */
8959 tcg_passres = tcg_res[pass];
8960 } else {
8961 tcg_passres = tcg_temp_new_i64();
8962 }
8963
8964 if (memop & MO_SIGN) {
8965 gen_helper_neon_mull_s16(tcg_passres, tcg_op, tcg_idx);
8966 } else {
8967 gen_helper_neon_mull_u16(tcg_passres, tcg_op, tcg_idx);
8968 }
8969 if (satop) {
8970 gen_helper_neon_addl_saturate_s32(tcg_passres, cpu_env,
8971 tcg_passres, tcg_passres);
8972 }
8973 tcg_temp_free_i32(tcg_op);
8974
8975 if (opcode == 0xa || opcode == 0xb) {
8976 continue;
8977 }
8978
8979 /* Accumulating op: handle accumulate step */
8980 read_vec_element(s, tcg_res[pass], rd, pass, MO_64);
8981
8982 switch (opcode) {
8983 case 0x2: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
8984 gen_helper_neon_addl_u32(tcg_res[pass], tcg_res[pass],
8985 tcg_passres);
8986 break;
8987 case 0x6: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
8988 gen_helper_neon_subl_u32(tcg_res[pass], tcg_res[pass],
8989 tcg_passres);
8990 break;
8991 case 0x7: /* SQDMLSL, SQDMLSL2 */
8992 gen_helper_neon_negl_u32(tcg_passres, tcg_passres);
8993 /* fall through */
8994 case 0x3: /* SQDMLAL, SQDMLAL2 */
8995 gen_helper_neon_addl_saturate_s32(tcg_res[pass], cpu_env,
8996 tcg_res[pass],
8997 tcg_passres);
8998 break;
8999 default:
9000 g_assert_not_reached();
9001 }
9002 tcg_temp_free_i64(tcg_passres);
9003 }
9004 tcg_temp_free_i32(tcg_idx);
Peter Maydell9f82e0f2014-02-20 10:35:49 +00009005
9006 if (is_scalar) {
9007 tcg_gen_ext32u_i64(tcg_res[0], tcg_res[0]);
9008 }
9009 }
9010
9011 if (is_scalar) {
9012 tcg_res[1] = tcg_const_i64(0);
Peter Maydellc44ad1f2014-02-20 10:35:49 +00009013 }
9014
9015 for (pass = 0; pass < 2; pass++) {
9016 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
9017 tcg_temp_free_i64(tcg_res[pass]);
9018 }
Peter Maydellf5e51e72014-02-20 10:35:48 +00009019 }
9020
9021 if (!TCGV_IS_UNUSED_PTR(fpst)) {
9022 tcg_temp_free_ptr(fpst);
9023 }
Alex Bennée384b26f2014-01-31 14:47:30 +00009024}
9025
9026/* C3.6.19 Crypto AES
9027 * 31 24 23 22 21 17 16 12 11 10 9 5 4 0
9028 * +-----------------+------+-----------+--------+-----+------+------+
9029 * | 0 1 0 0 1 1 1 0 | size | 1 0 1 0 0 | opcode | 1 0 | Rn | Rd |
9030 * +-----------------+------+-----------+--------+-----+------+------+
9031 */
9032static void disas_crypto_aes(DisasContext *s, uint32_t insn)
9033{
9034 unsupported_encoding(s, insn);
9035}
9036
9037/* C3.6.20 Crypto three-reg SHA
9038 * 31 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0
9039 * +-----------------+------+---+------+---+--------+-----+------+------+
9040 * | 0 1 0 1 1 1 1 0 | size | 0 | Rm | 0 | opcode | 0 0 | Rn | Rd |
9041 * +-----------------+------+---+------+---+--------+-----+------+------+
9042 */
9043static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
9044{
9045 unsupported_encoding(s, insn);
9046}
9047
9048/* C3.6.21 Crypto two-reg SHA
9049 * 31 24 23 22 21 17 16 12 11 10 9 5 4 0
9050 * +-----------------+------+-----------+--------+-----+------+------+
9051 * | 0 1 0 1 1 1 1 0 | size | 1 0 1 0 0 | opcode | 1 0 | Rn | Rd |
9052 * +-----------------+------+-----------+--------+-----+------+------+
9053 */
9054static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn)
9055{
9056 unsupported_encoding(s, insn);
9057}
9058
9059/* C3.6 Data processing - SIMD, inc Crypto
9060 *
9061 * As the decode gets a little complex we are using a table based
9062 * approach for this part of the decode.
9063 */
9064static const AArch64DecodeTable data_proc_simd[] = {
9065 /* pattern , mask , fn */
9066 { 0x0e200400, 0x9f200400, disas_simd_three_reg_same },
9067 { 0x0e200000, 0x9f200c00, disas_simd_three_reg_diff },
9068 { 0x0e200800, 0x9f3e0c00, disas_simd_two_reg_misc },
9069 { 0x0e300800, 0x9f3e0c00, disas_simd_across_lanes },
9070 { 0x0e000400, 0x9fe08400, disas_simd_copy },
Peter Maydell9f82e0f2014-02-20 10:35:49 +00009071 { 0x0f000000, 0x9f000400, disas_simd_indexed }, /* vector indexed */
Alex Bennée384b26f2014-01-31 14:47:30 +00009072 /* simd_mod_imm decode is a subset of simd_shift_imm, so must precede it */
9073 { 0x0f000400, 0x9ff80400, disas_simd_mod_imm },
9074 { 0x0f000400, 0x9f800400, disas_simd_shift_imm },
9075 { 0x0e000000, 0xbf208c00, disas_simd_tb },
9076 { 0x0e000800, 0xbf208c00, disas_simd_zip_trn },
9077 { 0x2e000000, 0xbf208400, disas_simd_ext },
9078 { 0x5e200400, 0xdf200400, disas_simd_scalar_three_reg_same },
9079 { 0x5e200000, 0xdf200c00, disas_simd_scalar_three_reg_diff },
9080 { 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc },
9081 { 0x5e300800, 0xdf3e0c00, disas_simd_scalar_pairwise },
9082 { 0x5e000400, 0xdfe08400, disas_simd_scalar_copy },
Peter Maydell9f82e0f2014-02-20 10:35:49 +00009083 { 0x5f000000, 0xdf000400, disas_simd_indexed }, /* scalar indexed */
Alex Bennée384b26f2014-01-31 14:47:30 +00009084 { 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm },
9085 { 0x4e280800, 0xff3e0c00, disas_crypto_aes },
9086 { 0x5e000000, 0xff208c00, disas_crypto_three_reg_sha },
9087 { 0x5e280800, 0xff3e0c00, disas_crypto_two_reg_sha },
9088 { 0x00000000, 0x00000000, NULL }
9089};
9090
Peter Maydellfaa0ba42013-12-23 23:27:30 +00009091static void disas_data_proc_simd(DisasContext *s, uint32_t insn)
9092{
9093 /* Note that this is called with all non-FP cases from
9094 * table C3-6 so it must UNDEF for entries not specifically
9095 * allocated to instructions in that table.
9096 */
Alex Bennée384b26f2014-01-31 14:47:30 +00009097 AArch64DecodeFn *fn = lookup_disas_fn(&data_proc_simd[0], insn);
9098 if (fn) {
9099 fn(s, insn);
9100 } else {
9101 unallocated_encoding(s);
9102 }
Peter Maydellfaa0ba42013-12-23 23:27:30 +00009103}
9104
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00009105/* C3.6 Data processing - SIMD and floating point */
9106static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
9107{
Peter Maydellfaa0ba42013-12-23 23:27:30 +00009108 if (extract32(insn, 28, 1) == 1 && extract32(insn, 30, 1) == 0) {
9109 disas_data_proc_fp(s, insn);
9110 } else {
9111 /* SIMD, including crypto */
9112 disas_data_proc_simd(s, insn);
9113 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00009114}
9115
9116/* C3.1 A64 instruction index by encoding */
Peter Maydell40f860c2013-12-17 19:42:31 +00009117static void disas_a64_insn(CPUARMState *env, DisasContext *s)
Alexander Graf14ade102013-09-03 20:12:10 +01009118{
9119 uint32_t insn;
9120
9121 insn = arm_ldl_code(env, s->pc, s->bswap_code);
9122 s->insn = insn;
9123 s->pc += 4;
9124
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00009125 switch (extract32(insn, 25, 4)) {
9126 case 0x0: case 0x1: case 0x2: case 0x3: /* UNALLOCATED */
Alexander Graf14ade102013-09-03 20:12:10 +01009127 unallocated_encoding(s);
9128 break;
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +00009129 case 0x8: case 0x9: /* Data processing - immediate */
9130 disas_data_proc_imm(s, insn);
9131 break;
9132 case 0xa: case 0xb: /* Branch, exception generation and system insns */
9133 disas_b_exc_sys(s, insn);
9134 break;
9135 case 0x4:
9136 case 0x6:
9137 case 0xc:
9138 case 0xe: /* Loads and stores */
9139 disas_ldst(s, insn);
9140 break;
9141 case 0x5:
9142 case 0xd: /* Data processing - register */
9143 disas_data_proc_reg(s, insn);
9144 break;
9145 case 0x7:
9146 case 0xf: /* Data processing - SIMD and floating point */
9147 disas_data_proc_simd_fp(s, insn);
9148 break;
9149 default:
9150 assert(FALSE); /* all 15 cases should be handled above */
9151 break;
Alexander Graf14ade102013-09-03 20:12:10 +01009152 }
Alexander Graf11e169d2013-12-17 19:42:32 +00009153
9154 /* if we allocated any temporaries, free them here */
9155 free_tmp_a64(s);
Peter Maydell40f860c2013-12-17 19:42:31 +00009156}
Alexander Graf14ade102013-09-03 20:12:10 +01009157
Peter Maydell40f860c2013-12-17 19:42:31 +00009158void gen_intermediate_code_internal_a64(ARMCPU *cpu,
9159 TranslationBlock *tb,
9160 bool search_pc)
9161{
9162 CPUState *cs = CPU(cpu);
9163 CPUARMState *env = &cpu->env;
9164 DisasContext dc1, *dc = &dc1;
9165 CPUBreakpoint *bp;
9166 uint16_t *gen_opc_end;
9167 int j, lj;
9168 target_ulong pc_start;
9169 target_ulong next_page_start;
9170 int num_insns;
9171 int max_insns;
9172
9173 pc_start = tb->pc;
9174
9175 dc->tb = tb;
9176
9177 gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
9178
9179 dc->is_jmp = DISAS_NEXT;
9180 dc->pc = pc_start;
9181 dc->singlestep_enabled = cs->singlestep_enabled;
9182 dc->condjmp = 0;
9183
9184 dc->aarch64 = 1;
9185 dc->thumb = 0;
9186 dc->bswap_code = 0;
9187 dc->condexec_mask = 0;
9188 dc->condexec_cond = 0;
9189#if !defined(CONFIG_USER_ONLY)
Peter Maydelld9ea7d22014-02-26 17:20:05 +00009190 dc->user = (ARM_TBFLAG_AA64_EL(tb->flags) == 0);
Peter Maydell40f860c2013-12-17 19:42:31 +00009191#endif
9192 dc->vfp_enabled = 0;
9193 dc->vec_len = 0;
9194 dc->vec_stride = 0;
Peter Maydell60322b32014-01-04 22:15:44 +00009195 dc->cp_regs = cpu->cp_regs;
9196 dc->current_pl = arm_current_pl(env);
Peter Maydell6c13ec22014-02-27 12:03:17 +00009197 dc->features = env->features;
Peter Maydell40f860c2013-12-17 19:42:31 +00009198
Alexander Graf11e169d2013-12-17 19:42:32 +00009199 init_tmp_a64_array(dc);
9200
Peter Maydell40f860c2013-12-17 19:42:31 +00009201 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
9202 lj = -1;
9203 num_insns = 0;
9204 max_insns = tb->cflags & CF_COUNT_MASK;
9205 if (max_insns == 0) {
9206 max_insns = CF_COUNT_MASK;
9207 }
9208
9209 gen_tb_start();
9210
9211 tcg_clear_temp_count();
9212
9213 do {
9214 if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
9215 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
9216 if (bp->pc == dc->pc) {
9217 gen_exception_insn(dc, 0, EXCP_DEBUG);
9218 /* Advance PC so that clearing the breakpoint will
9219 invalidate this TB. */
9220 dc->pc += 2;
9221 goto done_generating;
9222 }
9223 }
9224 }
9225
9226 if (search_pc) {
9227 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
9228 if (lj < j) {
9229 lj++;
9230 while (lj < j) {
9231 tcg_ctx.gen_opc_instr_start[lj++] = 0;
9232 }
9233 }
9234 tcg_ctx.gen_opc_pc[lj] = dc->pc;
9235 tcg_ctx.gen_opc_instr_start[lj] = 1;
9236 tcg_ctx.gen_opc_icount[lj] = num_insns;
9237 }
9238
9239 if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
9240 gen_io_start();
9241 }
9242
9243 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
9244 tcg_gen_debug_insn_start(dc->pc);
9245 }
9246
9247 disas_a64_insn(env, dc);
9248
9249 if (tcg_check_temp_count()) {
9250 fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
9251 dc->pc);
9252 }
9253
9254 /* Translation stops when a conditional branch is encountered.
9255 * Otherwise the subsequent code could get translated several times.
9256 * Also stop translation when a page boundary is reached. This
9257 * ensures prefetch aborts occur at the right place.
9258 */
9259 num_insns++;
9260 } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
9261 !cs->singlestep_enabled &&
9262 !singlestep &&
9263 dc->pc < next_page_start &&
9264 num_insns < max_insns);
9265
9266 if (tb->cflags & CF_LAST_IO) {
9267 gen_io_end();
9268 }
9269
9270 if (unlikely(cs->singlestep_enabled) && dc->is_jmp != DISAS_EXC) {
9271 /* Note that this means single stepping WFI doesn't halt the CPU.
9272 * For conditional branch insns this is harmless unreachable code as
9273 * gen_goto_tb() has already handled emitting the debug exception
9274 * (and thus a tb-jump is not possible when singlestepping).
9275 */
9276 assert(dc->is_jmp != DISAS_TB_JUMP);
9277 if (dc->is_jmp != DISAS_JUMP) {
9278 gen_a64_set_pc_im(dc->pc);
9279 }
9280 gen_exception(EXCP_DEBUG);
9281 } else {
9282 switch (dc->is_jmp) {
9283 case DISAS_NEXT:
9284 gen_goto_tb(dc, 1, dc->pc);
9285 break;
9286 default:
Peter Maydell40f860c2013-12-17 19:42:31 +00009287 case DISAS_UPDATE:
Peter Maydellfea50522014-01-04 22:15:45 +00009288 gen_a64_set_pc_im(dc->pc);
9289 /* fall through */
9290 case DISAS_JUMP:
Peter Maydell40f860c2013-12-17 19:42:31 +00009291 /* indicate that the hash table must be used to find the next TB */
9292 tcg_gen_exit_tb(0);
9293 break;
9294 case DISAS_TB_JUMP:
9295 case DISAS_EXC:
9296 case DISAS_SWI:
9297 break;
9298 case DISAS_WFI:
9299 /* This is a special case because we don't want to just halt the CPU
9300 * if trying to debug across a WFI.
9301 */
Peter Maydell1ed69e82014-02-26 17:20:06 +00009302 gen_a64_set_pc_im(dc->pc);
Peter Maydell40f860c2013-12-17 19:42:31 +00009303 gen_helper_wfi(cpu_env);
9304 break;
9305 }
9306 }
9307
9308done_generating:
9309 gen_tb_end(tb, num_insns);
9310 *tcg_ctx.gen_opc_ptr = INDEX_op_end;
9311
9312#ifdef DEBUG_DISAS
9313 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
9314 qemu_log("----------------\n");
9315 qemu_log("IN: %s\n", lookup_symbol(pc_start));
9316 log_target_disas(env, pc_start, dc->pc - pc_start,
Claudio Fontana999b53e2014-02-05 17:27:28 +00009317 4 | (dc->bswap_code << 1));
Peter Maydell40f860c2013-12-17 19:42:31 +00009318 qemu_log("\n");
9319 }
9320#endif
9321 if (search_pc) {
9322 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
9323 lj++;
9324 while (lj <= j) {
9325 tcg_ctx.gen_opc_instr_start[lj++] = 0;
9326 }
9327 } else {
9328 tb->size = dc->pc - pc_start;
9329 tb->icount = num_insns;
Alexander Graf14ade102013-09-03 20:12:10 +01009330 }
9331}