Statistics
| Branch: | Revision:

root / target-arm / translate-a64.c @ 626187d8

History | View | Annotate | Download (274.6 kB)

1 14ade10f Alexander Graf
/*
2 14ade10f Alexander Graf
 *  AArch64 translation
3 14ade10f Alexander Graf
 *
4 14ade10f Alexander Graf
 *  Copyright (c) 2013 Alexander Graf <agraf@suse.de>
5 14ade10f Alexander Graf
 *
6 14ade10f Alexander Graf
 * This library is free software; you can redistribute it and/or
7 14ade10f Alexander Graf
 * modify it under the terms of the GNU Lesser General Public
8 14ade10f Alexander Graf
 * License as published by the Free Software Foundation; either
9 14ade10f Alexander Graf
 * version 2 of the License, or (at your option) any later version.
10 14ade10f Alexander Graf
 *
11 14ade10f Alexander Graf
 * This library is distributed in the hope that it will be useful,
12 14ade10f Alexander Graf
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 14ade10f Alexander Graf
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 14ade10f Alexander Graf
 * Lesser General Public License for more details.
15 14ade10f Alexander Graf
 *
16 14ade10f Alexander Graf
 * You should have received a copy of the GNU Lesser General Public
17 14ade10f Alexander Graf
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 14ade10f Alexander Graf
 */
19 14ade10f Alexander Graf
#include <stdarg.h>
20 14ade10f Alexander Graf
#include <stdlib.h>
21 14ade10f Alexander Graf
#include <stdio.h>
22 14ade10f Alexander Graf
#include <string.h>
23 14ade10f Alexander Graf
#include <inttypes.h>
24 14ade10f Alexander Graf
25 14ade10f Alexander Graf
#include "cpu.h"
26 14ade10f Alexander Graf
#include "tcg-op.h"
27 14ade10f Alexander Graf
#include "qemu/log.h"
28 14ade10f Alexander Graf
#include "translate.h"
29 14ade10f Alexander Graf
#include "qemu/host-utils.h"
30 14ade10f Alexander Graf
31 40f860cd Peter Maydell
#include "exec/gen-icount.h"
32 40f860cd Peter Maydell
33 14ade10f Alexander Graf
#include "helper.h"
34 14ade10f Alexander Graf
#define GEN_HELPER 1
35 14ade10f Alexander Graf
#include "helper.h"
36 14ade10f Alexander Graf
37 14ade10f Alexander Graf
static TCGv_i64 cpu_X[32];
38 14ade10f Alexander Graf
static TCGv_i64 cpu_pc;
39 832ffa1c Alexander Graf
static TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
40 14ade10f Alexander Graf
41 fa2ef212 Michael Matz
/* Load/store exclusive handling */
42 fa2ef212 Michael Matz
static TCGv_i64 cpu_exclusive_addr;
43 fa2ef212 Michael Matz
static TCGv_i64 cpu_exclusive_val;
44 fa2ef212 Michael Matz
static TCGv_i64 cpu_exclusive_high;
45 fa2ef212 Michael Matz
#ifdef CONFIG_USER_ONLY
46 fa2ef212 Michael Matz
static TCGv_i64 cpu_exclusive_test;
47 fa2ef212 Michael Matz
static TCGv_i32 cpu_exclusive_info;
48 fa2ef212 Michael Matz
#endif
49 fa2ef212 Michael Matz
50 14ade10f Alexander Graf
static const char *regnames[] = {
51 14ade10f Alexander Graf
    "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
52 14ade10f Alexander Graf
    "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
53 14ade10f Alexander Graf
    "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
54 14ade10f Alexander Graf
    "x24", "x25", "x26", "x27", "x28", "x29", "lr", "sp"
55 14ade10f Alexander Graf
};
56 14ade10f Alexander Graf
57 832ffa1c Alexander Graf
enum a64_shift_type {
58 832ffa1c Alexander Graf
    A64_SHIFT_TYPE_LSL = 0,
59 832ffa1c Alexander Graf
    A64_SHIFT_TYPE_LSR = 1,
60 832ffa1c Alexander Graf
    A64_SHIFT_TYPE_ASR = 2,
61 832ffa1c Alexander Graf
    A64_SHIFT_TYPE_ROR = 3
62 832ffa1c Alexander Graf
};
63 832ffa1c Alexander Graf
64 384b26fb Alex Bennée
/* Table based decoder typedefs - used when the relevant bits for decode
65 384b26fb Alex Bennée
 * are too awkwardly scattered across the instruction (eg SIMD).
66 384b26fb Alex Bennée
 */
67 384b26fb Alex Bennée
typedef void AArch64DecodeFn(DisasContext *s, uint32_t insn);
68 384b26fb Alex Bennée
69 384b26fb Alex Bennée
typedef struct AArch64DecodeTable {
70 384b26fb Alex Bennée
    uint32_t pattern;
71 384b26fb Alex Bennée
    uint32_t mask;
72 384b26fb Alex Bennée
    AArch64DecodeFn *disas_fn;
73 384b26fb Alex Bennée
} AArch64DecodeTable;
74 384b26fb Alex Bennée
75 1f8a73af Peter Maydell
/* Function prototype for gen_ functions for calling Neon helpers */
76 1f8a73af Peter Maydell
typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32);
77 6d9571f7 Peter Maydell
typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32);
78 d980fd59 Peter Maydell
typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);
79 d980fd59 Peter Maydell
typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64);
80 8908f4d1 Alex Bennée
typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
81 8908f4d1 Alex Bennée
typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
82 1f8a73af Peter Maydell
83 14ade10f Alexander Graf
/* initialize TCG globals.  */
84 14ade10f Alexander Graf
void a64_translate_init(void)
85 14ade10f Alexander Graf
{
86 14ade10f Alexander Graf
    int i;
87 14ade10f Alexander Graf
88 14ade10f Alexander Graf
    cpu_pc = tcg_global_mem_new_i64(TCG_AREG0,
89 14ade10f Alexander Graf
                                    offsetof(CPUARMState, pc),
90 14ade10f Alexander Graf
                                    "pc");
91 14ade10f Alexander Graf
    for (i = 0; i < 32; i++) {
92 14ade10f Alexander Graf
        cpu_X[i] = tcg_global_mem_new_i64(TCG_AREG0,
93 14ade10f Alexander Graf
                                          offsetof(CPUARMState, xregs[i]),
94 14ade10f Alexander Graf
                                          regnames[i]);
95 14ade10f Alexander Graf
    }
96 14ade10f Alexander Graf
97 832ffa1c Alexander Graf
    cpu_NF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, NF), "NF");
98 832ffa1c Alexander Graf
    cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF");
99 832ffa1c Alexander Graf
    cpu_CF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, CF), "CF");
100 832ffa1c Alexander Graf
    cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF");
101 fa2ef212 Michael Matz
102 fa2ef212 Michael Matz
    cpu_exclusive_addr = tcg_global_mem_new_i64(TCG_AREG0,
103 fa2ef212 Michael Matz
        offsetof(CPUARMState, exclusive_addr), "exclusive_addr");
104 fa2ef212 Michael Matz
    cpu_exclusive_val = tcg_global_mem_new_i64(TCG_AREG0,
105 fa2ef212 Michael Matz
        offsetof(CPUARMState, exclusive_val), "exclusive_val");
106 fa2ef212 Michael Matz
    cpu_exclusive_high = tcg_global_mem_new_i64(TCG_AREG0,
107 fa2ef212 Michael Matz
        offsetof(CPUARMState, exclusive_high), "exclusive_high");
108 fa2ef212 Michael Matz
#ifdef CONFIG_USER_ONLY
109 fa2ef212 Michael Matz
    cpu_exclusive_test = tcg_global_mem_new_i64(TCG_AREG0,
110 fa2ef212 Michael Matz
        offsetof(CPUARMState, exclusive_test), "exclusive_test");
111 fa2ef212 Michael Matz
    cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
112 fa2ef212 Michael Matz
        offsetof(CPUARMState, exclusive_info), "exclusive_info");
113 fa2ef212 Michael Matz
#endif
114 14ade10f Alexander Graf
}
115 14ade10f Alexander Graf
116 14ade10f Alexander Graf
void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
117 14ade10f Alexander Graf
                            fprintf_function cpu_fprintf, int flags)
118 14ade10f Alexander Graf
{
119 14ade10f Alexander Graf
    ARMCPU *cpu = ARM_CPU(cs);
120 14ade10f Alexander Graf
    CPUARMState *env = &cpu->env;
121 d356312f Peter Maydell
    uint32_t psr = pstate_read(env);
122 14ade10f Alexander Graf
    int i;
123 14ade10f Alexander Graf
124 14ade10f Alexander Graf
    cpu_fprintf(f, "PC=%016"PRIx64"  SP=%016"PRIx64"\n",
125 14ade10f Alexander Graf
            env->pc, env->xregs[31]);
126 14ade10f Alexander Graf
    for (i = 0; i < 31; i++) {
127 14ade10f Alexander Graf
        cpu_fprintf(f, "X%02d=%016"PRIx64, i, env->xregs[i]);
128 14ade10f Alexander Graf
        if ((i % 4) == 3) {
129 14ade10f Alexander Graf
            cpu_fprintf(f, "\n");
130 14ade10f Alexander Graf
        } else {
131 14ade10f Alexander Graf
            cpu_fprintf(f, " ");
132 14ade10f Alexander Graf
        }
133 14ade10f Alexander Graf
    }
134 d356312f Peter Maydell
    cpu_fprintf(f, "PSTATE=%08x (flags %c%c%c%c)\n",
135 d356312f Peter Maydell
                psr,
136 d356312f Peter Maydell
                psr & PSTATE_N ? 'N' : '-',
137 d356312f Peter Maydell
                psr & PSTATE_Z ? 'Z' : '-',
138 d356312f Peter Maydell
                psr & PSTATE_C ? 'C' : '-',
139 d356312f Peter Maydell
                psr & PSTATE_V ? 'V' : '-');
140 14ade10f Alexander Graf
    cpu_fprintf(f, "\n");
141 f6d8a314 Alexander Graf
142 f6d8a314 Alexander Graf
    if (flags & CPU_DUMP_FPU) {
143 f6d8a314 Alexander Graf
        int numvfpregs = 32;
144 f6d8a314 Alexander Graf
        for (i = 0; i < numvfpregs; i += 2) {
145 f6d8a314 Alexander Graf
            uint64_t vlo = float64_val(env->vfp.regs[i * 2]);
146 f6d8a314 Alexander Graf
            uint64_t vhi = float64_val(env->vfp.regs[(i * 2) + 1]);
147 f6d8a314 Alexander Graf
            cpu_fprintf(f, "q%02d=%016" PRIx64 ":%016" PRIx64 " ",
148 f6d8a314 Alexander Graf
                        i, vhi, vlo);
149 f6d8a314 Alexander Graf
            vlo = float64_val(env->vfp.regs[(i + 1) * 2]);
150 f6d8a314 Alexander Graf
            vhi = float64_val(env->vfp.regs[((i + 1) * 2) + 1]);
151 f6d8a314 Alexander Graf
            cpu_fprintf(f, "q%02d=%016" PRIx64 ":%016" PRIx64 "\n",
152 f6d8a314 Alexander Graf
                        i + 1, vhi, vlo);
153 f6d8a314 Alexander Graf
        }
154 f6d8a314 Alexander Graf
        cpu_fprintf(f, "FPCR: %08x  FPSR: %08x\n",
155 f6d8a314 Alexander Graf
                    vfp_get_fpcr(env), vfp_get_fpsr(env));
156 f6d8a314 Alexander Graf
    }
157 14ade10f Alexander Graf
}
158 14ade10f Alexander Graf
159 4a08d475 Peter Maydell
static int get_mem_index(DisasContext *s)
160 4a08d475 Peter Maydell
{
161 4a08d475 Peter Maydell
#ifdef CONFIG_USER_ONLY
162 4a08d475 Peter Maydell
    return 1;
163 4a08d475 Peter Maydell
#else
164 4a08d475 Peter Maydell
    return s->user;
165 4a08d475 Peter Maydell
#endif
166 4a08d475 Peter Maydell
}
167 4a08d475 Peter Maydell
168 14ade10f Alexander Graf
void gen_a64_set_pc_im(uint64_t val)
169 14ade10f Alexander Graf
{
170 14ade10f Alexander Graf
    tcg_gen_movi_i64(cpu_pc, val);
171 14ade10f Alexander Graf
}
172 14ade10f Alexander Graf
173 14ade10f Alexander Graf
static void gen_exception(int excp)
174 14ade10f Alexander Graf
{
175 14ade10f Alexander Graf
    TCGv_i32 tmp = tcg_temp_new_i32();
176 14ade10f Alexander Graf
    tcg_gen_movi_i32(tmp, excp);
177 14ade10f Alexander Graf
    gen_helper_exception(cpu_env, tmp);
178 14ade10f Alexander Graf
    tcg_temp_free_i32(tmp);
179 14ade10f Alexander Graf
}
180 14ade10f Alexander Graf
181 14ade10f Alexander Graf
static void gen_exception_insn(DisasContext *s, int offset, int excp)
182 14ade10f Alexander Graf
{
183 14ade10f Alexander Graf
    gen_a64_set_pc_im(s->pc - offset);
184 14ade10f Alexander Graf
    gen_exception(excp);
185 40f860cd Peter Maydell
    s->is_jmp = DISAS_EXC;
186 40f860cd Peter Maydell
}
187 40f860cd Peter Maydell
188 40f860cd Peter Maydell
static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
189 40f860cd Peter Maydell
{
190 40f860cd Peter Maydell
    /* No direct tb linking with singlestep or deterministic io */
191 40f860cd Peter Maydell
    if (s->singlestep_enabled || (s->tb->cflags & CF_LAST_IO)) {
192 40f860cd Peter Maydell
        return false;
193 40f860cd Peter Maydell
    }
194 40f860cd Peter Maydell
195 40f860cd Peter Maydell
    /* Only link tbs from inside the same guest page */
196 40f860cd Peter Maydell
    if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
197 40f860cd Peter Maydell
        return false;
198 40f860cd Peter Maydell
    }
199 40f860cd Peter Maydell
200 40f860cd Peter Maydell
    return true;
201 40f860cd Peter Maydell
}
202 40f860cd Peter Maydell
203 40f860cd Peter Maydell
static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
204 40f860cd Peter Maydell
{
205 40f860cd Peter Maydell
    TranslationBlock *tb;
206 40f860cd Peter Maydell
207 40f860cd Peter Maydell
    tb = s->tb;
208 40f860cd Peter Maydell
    if (use_goto_tb(s, n, dest)) {
209 40f860cd Peter Maydell
        tcg_gen_goto_tb(n);
210 40f860cd Peter Maydell
        gen_a64_set_pc_im(dest);
211 40f860cd Peter Maydell
        tcg_gen_exit_tb((tcg_target_long)tb + n);
212 40f860cd Peter Maydell
        s->is_jmp = DISAS_TB_JUMP;
213 40f860cd Peter Maydell
    } else {
214 40f860cd Peter Maydell
        gen_a64_set_pc_im(dest);
215 40f860cd Peter Maydell
        if (s->singlestep_enabled) {
216 40f860cd Peter Maydell
            gen_exception(EXCP_DEBUG);
217 40f860cd Peter Maydell
        }
218 40f860cd Peter Maydell
        tcg_gen_exit_tb(0);
219 40f860cd Peter Maydell
        s->is_jmp = DISAS_JUMP;
220 40f860cd Peter Maydell
    }
221 14ade10f Alexander Graf
}
222 14ade10f Alexander Graf
223 ad7ee8a2 Claudio Fontana
static void unallocated_encoding(DisasContext *s)
224 14ade10f Alexander Graf
{
225 14ade10f Alexander Graf
    gen_exception_insn(s, 4, EXCP_UDEF);
226 14ade10f Alexander Graf
}
227 14ade10f Alexander Graf
228 ad7ee8a2 Claudio Fontana
#define unsupported_encoding(s, insn)                                    \
229 ad7ee8a2 Claudio Fontana
    do {                                                                 \
230 ad7ee8a2 Claudio Fontana
        qemu_log_mask(LOG_UNIMP,                                         \
231 ad7ee8a2 Claudio Fontana
                      "%s:%d: unsupported instruction encoding 0x%08x "  \
232 ad7ee8a2 Claudio Fontana
                      "at pc=%016" PRIx64 "\n",                          \
233 ad7ee8a2 Claudio Fontana
                      __FILE__, __LINE__, insn, s->pc - 4);              \
234 ad7ee8a2 Claudio Fontana
        unallocated_encoding(s);                                         \
235 ad7ee8a2 Claudio Fontana
    } while (0);
236 14ade10f Alexander Graf
237 11e169de Alexander Graf
static void init_tmp_a64_array(DisasContext *s)
238 11e169de Alexander Graf
{
239 11e169de Alexander Graf
#ifdef CONFIG_DEBUG_TCG
240 11e169de Alexander Graf
    int i;
241 11e169de Alexander Graf
    for (i = 0; i < ARRAY_SIZE(s->tmp_a64); i++) {
242 11e169de Alexander Graf
        TCGV_UNUSED_I64(s->tmp_a64[i]);
243 11e169de Alexander Graf
    }
244 11e169de Alexander Graf
#endif
245 11e169de Alexander Graf
    s->tmp_a64_count = 0;
246 11e169de Alexander Graf
}
247 11e169de Alexander Graf
248 11e169de Alexander Graf
static void free_tmp_a64(DisasContext *s)
249 11e169de Alexander Graf
{
250 11e169de Alexander Graf
    int i;
251 11e169de Alexander Graf
    for (i = 0; i < s->tmp_a64_count; i++) {
252 11e169de Alexander Graf
        tcg_temp_free_i64(s->tmp_a64[i]);
253 11e169de Alexander Graf
    }
254 11e169de Alexander Graf
    init_tmp_a64_array(s);
255 11e169de Alexander Graf
}
256 11e169de Alexander Graf
257 11e169de Alexander Graf
static TCGv_i64 new_tmp_a64(DisasContext *s)
258 11e169de Alexander Graf
{
259 11e169de Alexander Graf
    assert(s->tmp_a64_count < TMP_A64_MAX);
260 11e169de Alexander Graf
    return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64();
261 11e169de Alexander Graf
}
262 11e169de Alexander Graf
263 11e169de Alexander Graf
static TCGv_i64 new_tmp_a64_zero(DisasContext *s)
264 11e169de Alexander Graf
{
265 11e169de Alexander Graf
    TCGv_i64 t = new_tmp_a64(s);
266 11e169de Alexander Graf
    tcg_gen_movi_i64(t, 0);
267 11e169de Alexander Graf
    return t;
268 11e169de Alexander Graf
}
269 11e169de Alexander Graf
270 71b46089 Alexander Graf
/*
271 71b46089 Alexander Graf
 * Register access functions
272 71b46089 Alexander Graf
 *
273 71b46089 Alexander Graf
 * These functions are used for directly accessing a register in where
274 71b46089 Alexander Graf
 * changes to the final register value are likely to be made. If you
275 71b46089 Alexander Graf
 * need to use a register for temporary calculation (e.g. index type
276 71b46089 Alexander Graf
 * operations) use the read_* form.
277 71b46089 Alexander Graf
 *
278 71b46089 Alexander Graf
 * B1.2.1 Register mappings
279 71b46089 Alexander Graf
 *
280 71b46089 Alexander Graf
 * In instruction register encoding 31 can refer to ZR (zero register) or
281 71b46089 Alexander Graf
 * the SP (stack pointer) depending on context. In QEMU's case we map SP
282 71b46089 Alexander Graf
 * to cpu_X[31] and ZR accesses to a temporary which can be discarded.
283 71b46089 Alexander Graf
 * This is the point of the _sp forms.
284 71b46089 Alexander Graf
 */
285 11e169de Alexander Graf
static TCGv_i64 cpu_reg(DisasContext *s, int reg)
286 11e169de Alexander Graf
{
287 11e169de Alexander Graf
    if (reg == 31) {
288 11e169de Alexander Graf
        return new_tmp_a64_zero(s);
289 11e169de Alexander Graf
    } else {
290 11e169de Alexander Graf
        return cpu_X[reg];
291 11e169de Alexander Graf
    }
292 11e169de Alexander Graf
}
293 11e169de Alexander Graf
294 71b46089 Alexander Graf
/* register access for when 31 == SP */
295 71b46089 Alexander Graf
static TCGv_i64 cpu_reg_sp(DisasContext *s, int reg)
296 71b46089 Alexander Graf
{
297 71b46089 Alexander Graf
    return cpu_X[reg];
298 71b46089 Alexander Graf
}
299 71b46089 Alexander Graf
300 60e53388 Alexander Graf
/* read a cpu register in 32bit/64bit mode. Returns a TCGv_i64
301 60e53388 Alexander Graf
 * representing the register contents. This TCGv is an auto-freed
302 60e53388 Alexander Graf
 * temporary so it need not be explicitly freed, and may be modified.
303 60e53388 Alexander Graf
 */
304 60e53388 Alexander Graf
static TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
305 60e53388 Alexander Graf
{
306 60e53388 Alexander Graf
    TCGv_i64 v = new_tmp_a64(s);
307 60e53388 Alexander Graf
    if (reg != 31) {
308 60e53388 Alexander Graf
        if (sf) {
309 60e53388 Alexander Graf
            tcg_gen_mov_i64(v, cpu_X[reg]);
310 60e53388 Alexander Graf
        } else {
311 60e53388 Alexander Graf
            tcg_gen_ext32u_i64(v, cpu_X[reg]);
312 60e53388 Alexander Graf
        }
313 60e53388 Alexander Graf
    } else {
314 60e53388 Alexander Graf
        tcg_gen_movi_i64(v, 0);
315 60e53388 Alexander Graf
    }
316 60e53388 Alexander Graf
    return v;
317 60e53388 Alexander Graf
}
318 60e53388 Alexander Graf
319 4a08d475 Peter Maydell
static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
320 4a08d475 Peter Maydell
{
321 4a08d475 Peter Maydell
    TCGv_i64 v = new_tmp_a64(s);
322 4a08d475 Peter Maydell
    if (sf) {
323 4a08d475 Peter Maydell
        tcg_gen_mov_i64(v, cpu_X[reg]);
324 4a08d475 Peter Maydell
    } else {
325 4a08d475 Peter Maydell
        tcg_gen_ext32u_i64(v, cpu_X[reg]);
326 4a08d475 Peter Maydell
    }
327 4a08d475 Peter Maydell
    return v;
328 4a08d475 Peter Maydell
}
329 4a08d475 Peter Maydell
330 72430bf5 Alex Bennée
/* Return the offset into CPUARMState of an element of specified
331 72430bf5 Alex Bennée
 * size, 'element' places in from the least significant end of
332 72430bf5 Alex Bennée
 * the FP/vector register Qn.
333 72430bf5 Alex Bennée
 */
334 72430bf5 Alex Bennée
static inline int vec_reg_offset(int regno, int element, TCGMemOp size)
335 72430bf5 Alex Bennée
{
336 72430bf5 Alex Bennée
    int offs = offsetof(CPUARMState, vfp.regs[regno * 2]);
337 72430bf5 Alex Bennée
#ifdef HOST_WORDS_BIGENDIAN
338 72430bf5 Alex Bennée
    /* This is complicated slightly because vfp.regs[2n] is
339 72430bf5 Alex Bennée
     * still the low half and  vfp.regs[2n+1] the high half
340 72430bf5 Alex Bennée
     * of the 128 bit vector, even on big endian systems.
341 72430bf5 Alex Bennée
     * Calculate the offset assuming a fully bigendian 128 bits,
342 72430bf5 Alex Bennée
     * then XOR to account for the order of the two 64 bit halves.
343 72430bf5 Alex Bennée
     */
344 72430bf5 Alex Bennée
    offs += (16 - ((element + 1) * (1 << size)));
345 72430bf5 Alex Bennée
    offs ^= 8;
346 72430bf5 Alex Bennée
#else
347 72430bf5 Alex Bennée
    offs += element * (1 << size);
348 72430bf5 Alex Bennée
#endif
349 72430bf5 Alex Bennée
    return offs;
350 72430bf5 Alex Bennée
}
351 72430bf5 Alex Bennée
352 e2f90565 Peter Maydell
/* Return the offset into CPUARMState of a slice (from
353 e2f90565 Peter Maydell
 * the least significant end) of FP register Qn (ie
354 e2f90565 Peter Maydell
 * Dn, Sn, Hn or Bn).
355 e2f90565 Peter Maydell
 * (Note that this is not the same mapping as for A32; see cpu.h)
356 e2f90565 Peter Maydell
 */
357 e2f90565 Peter Maydell
static inline int fp_reg_offset(int regno, TCGMemOp size)
358 e2f90565 Peter Maydell
{
359 e2f90565 Peter Maydell
    int offs = offsetof(CPUARMState, vfp.regs[regno * 2]);
360 e2f90565 Peter Maydell
#ifdef HOST_WORDS_BIGENDIAN
361 e2f90565 Peter Maydell
    offs += (8 - (1 << size));
362 e2f90565 Peter Maydell
#endif
363 e2f90565 Peter Maydell
    return offs;
364 e2f90565 Peter Maydell
}
365 e2f90565 Peter Maydell
366 e2f90565 Peter Maydell
/* Offset of the high half of the 128 bit vector Qn */
367 e2f90565 Peter Maydell
static inline int fp_reg_hi_offset(int regno)
368 e2f90565 Peter Maydell
{
369 e2f90565 Peter Maydell
    return offsetof(CPUARMState, vfp.regs[regno * 2 + 1]);
370 e2f90565 Peter Maydell
}
371 e2f90565 Peter Maydell
372 ec73d2e0 Alexander Graf
/* Convenience accessors for reading and writing single and double
373 ec73d2e0 Alexander Graf
 * FP registers. Writing clears the upper parts of the associated
374 ec73d2e0 Alexander Graf
 * 128 bit vector register, as required by the architecture.
375 ec73d2e0 Alexander Graf
 * Note that unlike the GP register accessors, the values returned
376 ec73d2e0 Alexander Graf
 * by the read functions must be manually freed.
377 ec73d2e0 Alexander Graf
 */
378 ec73d2e0 Alexander Graf
static TCGv_i64 read_fp_dreg(DisasContext *s, int reg)
379 ec73d2e0 Alexander Graf
{
380 ec73d2e0 Alexander Graf
    TCGv_i64 v = tcg_temp_new_i64();
381 ec73d2e0 Alexander Graf
382 ec73d2e0 Alexander Graf
    tcg_gen_ld_i64(v, cpu_env, fp_reg_offset(reg, MO_64));
383 ec73d2e0 Alexander Graf
    return v;
384 ec73d2e0 Alexander Graf
}
385 ec73d2e0 Alexander Graf
386 ec73d2e0 Alexander Graf
static TCGv_i32 read_fp_sreg(DisasContext *s, int reg)
387 ec73d2e0 Alexander Graf
{
388 ec73d2e0 Alexander Graf
    TCGv_i32 v = tcg_temp_new_i32();
389 ec73d2e0 Alexander Graf
390 ec73d2e0 Alexander Graf
    tcg_gen_ld_i32(v, cpu_env, fp_reg_offset(reg, MO_32));
391 ec73d2e0 Alexander Graf
    return v;
392 ec73d2e0 Alexander Graf
}
393 ec73d2e0 Alexander Graf
394 ec73d2e0 Alexander Graf
static void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v)
395 ec73d2e0 Alexander Graf
{
396 ec73d2e0 Alexander Graf
    TCGv_i64 tcg_zero = tcg_const_i64(0);
397 ec73d2e0 Alexander Graf
398 ec73d2e0 Alexander Graf
    tcg_gen_st_i64(v, cpu_env, fp_reg_offset(reg, MO_64));
399 ec73d2e0 Alexander Graf
    tcg_gen_st_i64(tcg_zero, cpu_env, fp_reg_hi_offset(reg));
400 ec73d2e0 Alexander Graf
    tcg_temp_free_i64(tcg_zero);
401 ec73d2e0 Alexander Graf
}
402 ec73d2e0 Alexander Graf
403 ec73d2e0 Alexander Graf
static void write_fp_sreg(DisasContext *s, int reg, TCGv_i32 v)
404 ec73d2e0 Alexander Graf
{
405 ec73d2e0 Alexander Graf
    TCGv_i64 tmp = tcg_temp_new_i64();
406 ec73d2e0 Alexander Graf
407 ec73d2e0 Alexander Graf
    tcg_gen_extu_i32_i64(tmp, v);
408 ec73d2e0 Alexander Graf
    write_fp_dreg(s, reg, tmp);
409 ec73d2e0 Alexander Graf
    tcg_temp_free_i64(tmp);
410 ec73d2e0 Alexander Graf
}
411 ec73d2e0 Alexander Graf
412 ec73d2e0 Alexander Graf
static TCGv_ptr get_fpstatus_ptr(void)
413 ec73d2e0 Alexander Graf
{
414 ec73d2e0 Alexander Graf
    TCGv_ptr statusptr = tcg_temp_new_ptr();
415 ec73d2e0 Alexander Graf
    int offset;
416 ec73d2e0 Alexander Graf
417 ec73d2e0 Alexander Graf
    /* In A64 all instructions (both FP and Neon) use the FPCR;
418 ec73d2e0 Alexander Graf
     * there is no equivalent of the A32 Neon "standard FPSCR value"
419 ec73d2e0 Alexander Graf
     * and all operations use vfp.fp_status.
420 ec73d2e0 Alexander Graf
     */
421 ec73d2e0 Alexander Graf
    offset = offsetof(CPUARMState, vfp.fp_status);
422 ec73d2e0 Alexander Graf
    tcg_gen_addi_ptr(statusptr, cpu_env, offset);
423 ec73d2e0 Alexander Graf
    return statusptr;
424 ec73d2e0 Alexander Graf
}
425 ec73d2e0 Alexander Graf
426 832ffa1c Alexander Graf
/* Set ZF and NF based on a 64 bit result. This is alas fiddlier
427 832ffa1c Alexander Graf
 * than the 32 bit equivalent.
428 832ffa1c Alexander Graf
 */
429 832ffa1c Alexander Graf
static inline void gen_set_NZ64(TCGv_i64 result)
430 832ffa1c Alexander Graf
{
431 832ffa1c Alexander Graf
    TCGv_i64 flag = tcg_temp_new_i64();
432 832ffa1c Alexander Graf
433 832ffa1c Alexander Graf
    tcg_gen_setcondi_i64(TCG_COND_NE, flag, result, 0);
434 832ffa1c Alexander Graf
    tcg_gen_trunc_i64_i32(cpu_ZF, flag);
435 832ffa1c Alexander Graf
    tcg_gen_shri_i64(flag, result, 32);
436 832ffa1c Alexander Graf
    tcg_gen_trunc_i64_i32(cpu_NF, flag);
437 832ffa1c Alexander Graf
    tcg_temp_free_i64(flag);
438 832ffa1c Alexander Graf
}
439 832ffa1c Alexander Graf
440 832ffa1c Alexander Graf
/* Set NZCV as for a logical operation: NZ as per result, CV cleared. */
441 832ffa1c Alexander Graf
static inline void gen_logic_CC(int sf, TCGv_i64 result)
442 832ffa1c Alexander Graf
{
443 832ffa1c Alexander Graf
    if (sf) {
444 832ffa1c Alexander Graf
        gen_set_NZ64(result);
445 832ffa1c Alexander Graf
    } else {
446 832ffa1c Alexander Graf
        tcg_gen_trunc_i64_i32(cpu_ZF, result);
447 832ffa1c Alexander Graf
        tcg_gen_trunc_i64_i32(cpu_NF, result);
448 832ffa1c Alexander Graf
    }
449 832ffa1c Alexander Graf
    tcg_gen_movi_i32(cpu_CF, 0);
450 832ffa1c Alexander Graf
    tcg_gen_movi_i32(cpu_VF, 0);
451 832ffa1c Alexander Graf
}
452 832ffa1c Alexander Graf
453 b0ff21b4 Alex Bennée
/* dest = T0 + T1; compute C, N, V and Z flags */
454 b0ff21b4 Alex Bennée
static void gen_add_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
455 b0ff21b4 Alex Bennée
{
456 b0ff21b4 Alex Bennée
    if (sf) {
457 b0ff21b4 Alex Bennée
        TCGv_i64 result, flag, tmp;
458 b0ff21b4 Alex Bennée
        result = tcg_temp_new_i64();
459 b0ff21b4 Alex Bennée
        flag = tcg_temp_new_i64();
460 b0ff21b4 Alex Bennée
        tmp = tcg_temp_new_i64();
461 b0ff21b4 Alex Bennée
462 b0ff21b4 Alex Bennée
        tcg_gen_movi_i64(tmp, 0);
463 b0ff21b4 Alex Bennée
        tcg_gen_add2_i64(result, flag, t0, tmp, t1, tmp);
464 b0ff21b4 Alex Bennée
465 b0ff21b4 Alex Bennée
        tcg_gen_trunc_i64_i32(cpu_CF, flag);
466 b0ff21b4 Alex Bennée
467 b0ff21b4 Alex Bennée
        gen_set_NZ64(result);
468 b0ff21b4 Alex Bennée
469 b0ff21b4 Alex Bennée
        tcg_gen_xor_i64(flag, result, t0);
470 b0ff21b4 Alex Bennée
        tcg_gen_xor_i64(tmp, t0, t1);
471 b0ff21b4 Alex Bennée
        tcg_gen_andc_i64(flag, flag, tmp);
472 b0ff21b4 Alex Bennée
        tcg_temp_free_i64(tmp);
473 b0ff21b4 Alex Bennée
        tcg_gen_shri_i64(flag, flag, 32);
474 b0ff21b4 Alex Bennée
        tcg_gen_trunc_i64_i32(cpu_VF, flag);
475 b0ff21b4 Alex Bennée
476 b0ff21b4 Alex Bennée
        tcg_gen_mov_i64(dest, result);
477 b0ff21b4 Alex Bennée
        tcg_temp_free_i64(result);
478 b0ff21b4 Alex Bennée
        tcg_temp_free_i64(flag);
479 b0ff21b4 Alex Bennée
    } else {
480 b0ff21b4 Alex Bennée
        /* 32 bit arithmetic */
481 b0ff21b4 Alex Bennée
        TCGv_i32 t0_32 = tcg_temp_new_i32();
482 b0ff21b4 Alex Bennée
        TCGv_i32 t1_32 = tcg_temp_new_i32();
483 b0ff21b4 Alex Bennée
        TCGv_i32 tmp = tcg_temp_new_i32();
484 b0ff21b4 Alex Bennée
485 b0ff21b4 Alex Bennée
        tcg_gen_movi_i32(tmp, 0);
486 b0ff21b4 Alex Bennée
        tcg_gen_trunc_i64_i32(t0_32, t0);
487 b0ff21b4 Alex Bennée
        tcg_gen_trunc_i64_i32(t1_32, t1);
488 b0ff21b4 Alex Bennée
        tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, t1_32, tmp);
489 b0ff21b4 Alex Bennée
        tcg_gen_mov_i32(cpu_ZF, cpu_NF);
490 b0ff21b4 Alex Bennée
        tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
491 b0ff21b4 Alex Bennée
        tcg_gen_xor_i32(tmp, t0_32, t1_32);
492 b0ff21b4 Alex Bennée
        tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
493 b0ff21b4 Alex Bennée
        tcg_gen_extu_i32_i64(dest, cpu_NF);
494 b0ff21b4 Alex Bennée
495 b0ff21b4 Alex Bennée
        tcg_temp_free_i32(tmp);
496 b0ff21b4 Alex Bennée
        tcg_temp_free_i32(t0_32);
497 b0ff21b4 Alex Bennée
        tcg_temp_free_i32(t1_32);
498 b0ff21b4 Alex Bennée
    }
499 b0ff21b4 Alex Bennée
}
500 b0ff21b4 Alex Bennée
501 b0ff21b4 Alex Bennée
/* dest = T0 - T1; compute C, N, V and Z flags */
502 b0ff21b4 Alex Bennée
static void gen_sub_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
503 b0ff21b4 Alex Bennée
{
504 b0ff21b4 Alex Bennée
    if (sf) {
505 b0ff21b4 Alex Bennée
        /* 64 bit arithmetic */
506 b0ff21b4 Alex Bennée
        TCGv_i64 result, flag, tmp;
507 b0ff21b4 Alex Bennée
508 b0ff21b4 Alex Bennée
        result = tcg_temp_new_i64();
509 b0ff21b4 Alex Bennée
        flag = tcg_temp_new_i64();
510 b0ff21b4 Alex Bennée
        tcg_gen_sub_i64(result, t0, t1);
511 b0ff21b4 Alex Bennée
512 b0ff21b4 Alex Bennée
        gen_set_NZ64(result);
513 b0ff21b4 Alex Bennée
514 b0ff21b4 Alex Bennée
        tcg_gen_setcond_i64(TCG_COND_GEU, flag, t0, t1);
515 b0ff21b4 Alex Bennée
        tcg_gen_trunc_i64_i32(cpu_CF, flag);
516 b0ff21b4 Alex Bennée
517 b0ff21b4 Alex Bennée
        tcg_gen_xor_i64(flag, result, t0);
518 b0ff21b4 Alex Bennée
        tmp = tcg_temp_new_i64();
519 b0ff21b4 Alex Bennée
        tcg_gen_xor_i64(tmp, t0, t1);
520 b0ff21b4 Alex Bennée
        tcg_gen_and_i64(flag, flag, tmp);
521 b0ff21b4 Alex Bennée
        tcg_temp_free_i64(tmp);
522 b0ff21b4 Alex Bennée
        tcg_gen_shri_i64(flag, flag, 32);
523 b0ff21b4 Alex Bennée
        tcg_gen_trunc_i64_i32(cpu_VF, flag);
524 b0ff21b4 Alex Bennée
        tcg_gen_mov_i64(dest, result);
525 b0ff21b4 Alex Bennée
        tcg_temp_free_i64(flag);
526 b0ff21b4 Alex Bennée
        tcg_temp_free_i64(result);
527 b0ff21b4 Alex Bennée
    } else {
528 b0ff21b4 Alex Bennée
        /* 32 bit arithmetic */
529 b0ff21b4 Alex Bennée
        TCGv_i32 t0_32 = tcg_temp_new_i32();
530 b0ff21b4 Alex Bennée
        TCGv_i32 t1_32 = tcg_temp_new_i32();
531 b0ff21b4 Alex Bennée
        TCGv_i32 tmp;
532 b0ff21b4 Alex Bennée
533 b0ff21b4 Alex Bennée
        tcg_gen_trunc_i64_i32(t0_32, t0);
534 b0ff21b4 Alex Bennée
        tcg_gen_trunc_i64_i32(t1_32, t1);
535 b0ff21b4 Alex Bennée
        tcg_gen_sub_i32(cpu_NF, t0_32, t1_32);
536 b0ff21b4 Alex Bennée
        tcg_gen_mov_i32(cpu_ZF, cpu_NF);
537 b0ff21b4 Alex Bennée
        tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0_32, t1_32);
538 b0ff21b4 Alex Bennée
        tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
539 b0ff21b4 Alex Bennée
        tmp = tcg_temp_new_i32();
540 b0ff21b4 Alex Bennée
        tcg_gen_xor_i32(tmp, t0_32, t1_32);
541 b0ff21b4 Alex Bennée
        tcg_temp_free_i32(t0_32);
542 b0ff21b4 Alex Bennée
        tcg_temp_free_i32(t1_32);
543 b0ff21b4 Alex Bennée
        tcg_gen_and_i32(cpu_VF, cpu_VF, tmp);
544 b0ff21b4 Alex Bennée
        tcg_temp_free_i32(tmp);
545 b0ff21b4 Alex Bennée
        tcg_gen_extu_i32_i64(dest, cpu_NF);
546 b0ff21b4 Alex Bennée
    }
547 b0ff21b4 Alex Bennée
}
548 b0ff21b4 Alex Bennée
549 643dbb07 Claudio Fontana
/* dest = T0 + T1 + CF; do not compute flags. */
550 643dbb07 Claudio Fontana
static void gen_adc(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
551 643dbb07 Claudio Fontana
{
552 643dbb07 Claudio Fontana
    TCGv_i64 flag = tcg_temp_new_i64();
553 643dbb07 Claudio Fontana
    tcg_gen_extu_i32_i64(flag, cpu_CF);
554 643dbb07 Claudio Fontana
    tcg_gen_add_i64(dest, t0, t1);
555 643dbb07 Claudio Fontana
    tcg_gen_add_i64(dest, dest, flag);
556 643dbb07 Claudio Fontana
    tcg_temp_free_i64(flag);
557 643dbb07 Claudio Fontana
558 643dbb07 Claudio Fontana
    if (!sf) {
559 643dbb07 Claudio Fontana
        tcg_gen_ext32u_i64(dest, dest);
560 643dbb07 Claudio Fontana
    }
561 643dbb07 Claudio Fontana
}
562 643dbb07 Claudio Fontana
563 643dbb07 Claudio Fontana
/* dest = T0 + T1 + CF; compute C, N, V and Z flags. */
564 643dbb07 Claudio Fontana
static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
565 643dbb07 Claudio Fontana
{
566 643dbb07 Claudio Fontana
    if (sf) {
567 643dbb07 Claudio Fontana
        TCGv_i64 result, cf_64, vf_64, tmp;
568 643dbb07 Claudio Fontana
        result = tcg_temp_new_i64();
569 643dbb07 Claudio Fontana
        cf_64 = tcg_temp_new_i64();
570 643dbb07 Claudio Fontana
        vf_64 = tcg_temp_new_i64();
571 643dbb07 Claudio Fontana
        tmp = tcg_const_i64(0);
572 643dbb07 Claudio Fontana
573 643dbb07 Claudio Fontana
        tcg_gen_extu_i32_i64(cf_64, cpu_CF);
574 643dbb07 Claudio Fontana
        tcg_gen_add2_i64(result, cf_64, t0, tmp, cf_64, tmp);
575 643dbb07 Claudio Fontana
        tcg_gen_add2_i64(result, cf_64, result, cf_64, t1, tmp);
576 643dbb07 Claudio Fontana
        tcg_gen_trunc_i64_i32(cpu_CF, cf_64);
577 643dbb07 Claudio Fontana
        gen_set_NZ64(result);
578 643dbb07 Claudio Fontana
579 643dbb07 Claudio Fontana
        tcg_gen_xor_i64(vf_64, result, t0);
580 643dbb07 Claudio Fontana
        tcg_gen_xor_i64(tmp, t0, t1);
581 643dbb07 Claudio Fontana
        tcg_gen_andc_i64(vf_64, vf_64, tmp);
582 643dbb07 Claudio Fontana
        tcg_gen_shri_i64(vf_64, vf_64, 32);
583 643dbb07 Claudio Fontana
        tcg_gen_trunc_i64_i32(cpu_VF, vf_64);
584 643dbb07 Claudio Fontana
585 643dbb07 Claudio Fontana
        tcg_gen_mov_i64(dest, result);
586 643dbb07 Claudio Fontana
587 643dbb07 Claudio Fontana
        tcg_temp_free_i64(tmp);
588 643dbb07 Claudio Fontana
        tcg_temp_free_i64(vf_64);
589 643dbb07 Claudio Fontana
        tcg_temp_free_i64(cf_64);
590 643dbb07 Claudio Fontana
        tcg_temp_free_i64(result);
591 643dbb07 Claudio Fontana
    } else {
592 643dbb07 Claudio Fontana
        TCGv_i32 t0_32, t1_32, tmp;
593 643dbb07 Claudio Fontana
        t0_32 = tcg_temp_new_i32();
594 643dbb07 Claudio Fontana
        t1_32 = tcg_temp_new_i32();
595 643dbb07 Claudio Fontana
        tmp = tcg_const_i32(0);
596 643dbb07 Claudio Fontana
597 643dbb07 Claudio Fontana
        tcg_gen_trunc_i64_i32(t0_32, t0);
598 643dbb07 Claudio Fontana
        tcg_gen_trunc_i64_i32(t1_32, t1);
599 643dbb07 Claudio Fontana
        tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, cpu_CF, tmp);
600 643dbb07 Claudio Fontana
        tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1_32, tmp);
601 643dbb07 Claudio Fontana
602 643dbb07 Claudio Fontana
        tcg_gen_mov_i32(cpu_ZF, cpu_NF);
603 643dbb07 Claudio Fontana
        tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
604 643dbb07 Claudio Fontana
        tcg_gen_xor_i32(tmp, t0_32, t1_32);
605 643dbb07 Claudio Fontana
        tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
606 643dbb07 Claudio Fontana
        tcg_gen_extu_i32_i64(dest, cpu_NF);
607 643dbb07 Claudio Fontana
608 643dbb07 Claudio Fontana
        tcg_temp_free_i32(tmp);
609 643dbb07 Claudio Fontana
        tcg_temp_free_i32(t1_32);
610 643dbb07 Claudio Fontana
        tcg_temp_free_i32(t0_32);
611 643dbb07 Claudio Fontana
    }
612 643dbb07 Claudio Fontana
}
613 643dbb07 Claudio Fontana
614 ad7ee8a2 Claudio Fontana
/*
615 4a08d475 Peter Maydell
 * Load/Store generators
616 4a08d475 Peter Maydell
 */
617 4a08d475 Peter Maydell
618 4a08d475 Peter Maydell
/*
619 4a08d475 Peter Maydell
 * Store from GPR register to memory
620 4a08d475 Peter Maydell
 */
621 4a08d475 Peter Maydell
static void do_gpr_st(DisasContext *s, TCGv_i64 source,
622 4a08d475 Peter Maydell
                      TCGv_i64 tcg_addr, int size)
623 4a08d475 Peter Maydell
{
624 4a08d475 Peter Maydell
    g_assert(size <= 3);
625 4a08d475 Peter Maydell
    tcg_gen_qemu_st_i64(source, tcg_addr, get_mem_index(s), MO_TE + size);
626 4a08d475 Peter Maydell
}
627 4a08d475 Peter Maydell
628 4a08d475 Peter Maydell
/*
629 4a08d475 Peter Maydell
 * Load from memory to GPR register
630 4a08d475 Peter Maydell
 */
631 4a08d475 Peter Maydell
static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
632 4a08d475 Peter Maydell
                      int size, bool is_signed, bool extend)
633 4a08d475 Peter Maydell
{
634 4a08d475 Peter Maydell
    TCGMemOp memop = MO_TE + size;
635 4a08d475 Peter Maydell
636 4a08d475 Peter Maydell
    g_assert(size <= 3);
637 4a08d475 Peter Maydell
638 4a08d475 Peter Maydell
    if (is_signed) {
639 4a08d475 Peter Maydell
        memop += MO_SIGN;
640 4a08d475 Peter Maydell
    }
641 4a08d475 Peter Maydell
642 4a08d475 Peter Maydell
    tcg_gen_qemu_ld_i64(dest, tcg_addr, get_mem_index(s), memop);
643 4a08d475 Peter Maydell
644 4a08d475 Peter Maydell
    if (extend && is_signed) {
645 4a08d475 Peter Maydell
        g_assert(size < 3);
646 4a08d475 Peter Maydell
        tcg_gen_ext32u_i64(dest, dest);
647 4a08d475 Peter Maydell
    }
648 4a08d475 Peter Maydell
}
649 4a08d475 Peter Maydell
650 4a08d475 Peter Maydell
/*
651 4a08d475 Peter Maydell
 * Store from FP register to memory
652 4a08d475 Peter Maydell
 */
653 4a08d475 Peter Maydell
static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
654 4a08d475 Peter Maydell
{
655 4a08d475 Peter Maydell
    /* This writes the bottom N bits of a 128 bit wide vector to memory */
656 4a08d475 Peter Maydell
    TCGv_i64 tmp = tcg_temp_new_i64();
657 e2f90565 Peter Maydell
    tcg_gen_ld_i64(tmp, cpu_env, fp_reg_offset(srcidx, MO_64));
658 4a08d475 Peter Maydell
    if (size < 4) {
659 4a08d475 Peter Maydell
        tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TE + size);
660 4a08d475 Peter Maydell
    } else {
661 4a08d475 Peter Maydell
        TCGv_i64 tcg_hiaddr = tcg_temp_new_i64();
662 4a08d475 Peter Maydell
        tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TEQ);
663 4a08d475 Peter Maydell
        tcg_gen_qemu_st64(tmp, tcg_addr, get_mem_index(s));
664 e2f90565 Peter Maydell
        tcg_gen_ld_i64(tmp, cpu_env, fp_reg_hi_offset(srcidx));
665 4a08d475 Peter Maydell
        tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
666 4a08d475 Peter Maydell
        tcg_gen_qemu_st_i64(tmp, tcg_hiaddr, get_mem_index(s), MO_TEQ);
667 4a08d475 Peter Maydell
        tcg_temp_free_i64(tcg_hiaddr);
668 4a08d475 Peter Maydell
    }
669 4a08d475 Peter Maydell
670 4a08d475 Peter Maydell
    tcg_temp_free_i64(tmp);
671 4a08d475 Peter Maydell
}
672 4a08d475 Peter Maydell
673 4a08d475 Peter Maydell
/*
674 4a08d475 Peter Maydell
 * Load from memory to FP register
675 4a08d475 Peter Maydell
 */
676 4a08d475 Peter Maydell
static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
677 4a08d475 Peter Maydell
{
678 4a08d475 Peter Maydell
    /* This always zero-extends and writes to a full 128 bit wide vector */
679 4a08d475 Peter Maydell
    TCGv_i64 tmplo = tcg_temp_new_i64();
680 4a08d475 Peter Maydell
    TCGv_i64 tmphi;
681 4a08d475 Peter Maydell
682 4a08d475 Peter Maydell
    if (size < 4) {
683 4a08d475 Peter Maydell
        TCGMemOp memop = MO_TE + size;
684 4a08d475 Peter Maydell
        tmphi = tcg_const_i64(0);
685 4a08d475 Peter Maydell
        tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop);
686 4a08d475 Peter Maydell
    } else {
687 4a08d475 Peter Maydell
        TCGv_i64 tcg_hiaddr;
688 4a08d475 Peter Maydell
        tmphi = tcg_temp_new_i64();
689 4a08d475 Peter Maydell
        tcg_hiaddr = tcg_temp_new_i64();
690 4a08d475 Peter Maydell
691 4a08d475 Peter Maydell
        tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), MO_TEQ);
692 4a08d475 Peter Maydell
        tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
693 4a08d475 Peter Maydell
        tcg_gen_qemu_ld_i64(tmphi, tcg_hiaddr, get_mem_index(s), MO_TEQ);
694 4a08d475 Peter Maydell
        tcg_temp_free_i64(tcg_hiaddr);
695 4a08d475 Peter Maydell
    }
696 4a08d475 Peter Maydell
697 e2f90565 Peter Maydell
    tcg_gen_st_i64(tmplo, cpu_env, fp_reg_offset(destidx, MO_64));
698 e2f90565 Peter Maydell
    tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(destidx));
699 4a08d475 Peter Maydell
700 4a08d475 Peter Maydell
    tcg_temp_free_i64(tmplo);
701 4a08d475 Peter Maydell
    tcg_temp_free_i64(tmphi);
702 4a08d475 Peter Maydell
}
703 4a08d475 Peter Maydell
704 229b7a05 Alex Bennée
/*
705 72430bf5 Alex Bennée
 * Vector load/store helpers.
706 72430bf5 Alex Bennée
 *
707 72430bf5 Alex Bennée
 * The principal difference between this and a FP load is that we don't
708 72430bf5 Alex Bennée
 * zero extend as we are filling a partial chunk of the vector register.
709 72430bf5 Alex Bennée
 * These functions don't support 128 bit loads/stores, which would be
710 72430bf5 Alex Bennée
 * normal load/store operations.
711 a08582f4 Peter Maydell
 *
712 a08582f4 Peter Maydell
 * The _i32 versions are useful when operating on 32 bit quantities
713 a08582f4 Peter Maydell
 * (eg for floating point single or using Neon helper functions).
714 72430bf5 Alex Bennée
 */
715 72430bf5 Alex Bennée
716 72430bf5 Alex Bennée
/* Get value of an element within a vector register */
717 72430bf5 Alex Bennée
static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
718 72430bf5 Alex Bennée
                             int element, TCGMemOp memop)
719 72430bf5 Alex Bennée
{
720 72430bf5 Alex Bennée
    int vect_off = vec_reg_offset(srcidx, element, memop & MO_SIZE);
721 72430bf5 Alex Bennée
    switch (memop) {
722 72430bf5 Alex Bennée
    case MO_8:
723 72430bf5 Alex Bennée
        tcg_gen_ld8u_i64(tcg_dest, cpu_env, vect_off);
724 72430bf5 Alex Bennée
        break;
725 72430bf5 Alex Bennée
    case MO_16:
726 72430bf5 Alex Bennée
        tcg_gen_ld16u_i64(tcg_dest, cpu_env, vect_off);
727 72430bf5 Alex Bennée
        break;
728 72430bf5 Alex Bennée
    case MO_32:
729 72430bf5 Alex Bennée
        tcg_gen_ld32u_i64(tcg_dest, cpu_env, vect_off);
730 72430bf5 Alex Bennée
        break;
731 72430bf5 Alex Bennée
    case MO_8|MO_SIGN:
732 72430bf5 Alex Bennée
        tcg_gen_ld8s_i64(tcg_dest, cpu_env, vect_off);
733 72430bf5 Alex Bennée
        break;
734 72430bf5 Alex Bennée
    case MO_16|MO_SIGN:
735 72430bf5 Alex Bennée
        tcg_gen_ld16s_i64(tcg_dest, cpu_env, vect_off);
736 72430bf5 Alex Bennée
        break;
737 72430bf5 Alex Bennée
    case MO_32|MO_SIGN:
738 72430bf5 Alex Bennée
        tcg_gen_ld32s_i64(tcg_dest, cpu_env, vect_off);
739 72430bf5 Alex Bennée
        break;
740 72430bf5 Alex Bennée
    case MO_64:
741 72430bf5 Alex Bennée
    case MO_64|MO_SIGN:
742 72430bf5 Alex Bennée
        tcg_gen_ld_i64(tcg_dest, cpu_env, vect_off);
743 72430bf5 Alex Bennée
        break;
744 72430bf5 Alex Bennée
    default:
745 72430bf5 Alex Bennée
        g_assert_not_reached();
746 72430bf5 Alex Bennée
    }
747 72430bf5 Alex Bennée
}
748 72430bf5 Alex Bennée
749 a08582f4 Peter Maydell
static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx,
750 a08582f4 Peter Maydell
                                 int element, TCGMemOp memop)
751 a08582f4 Peter Maydell
{
752 a08582f4 Peter Maydell
    int vect_off = vec_reg_offset(srcidx, element, memop & MO_SIZE);
753 a08582f4 Peter Maydell
    switch (memop) {
754 a08582f4 Peter Maydell
    case MO_8:
755 a08582f4 Peter Maydell
        tcg_gen_ld8u_i32(tcg_dest, cpu_env, vect_off);
756 a08582f4 Peter Maydell
        break;
757 a08582f4 Peter Maydell
    case MO_16:
758 a08582f4 Peter Maydell
        tcg_gen_ld16u_i32(tcg_dest, cpu_env, vect_off);
759 a08582f4 Peter Maydell
        break;
760 a08582f4 Peter Maydell
    case MO_8|MO_SIGN:
761 a08582f4 Peter Maydell
        tcg_gen_ld8s_i32(tcg_dest, cpu_env, vect_off);
762 a08582f4 Peter Maydell
        break;
763 a08582f4 Peter Maydell
    case MO_16|MO_SIGN:
764 a08582f4 Peter Maydell
        tcg_gen_ld16s_i32(tcg_dest, cpu_env, vect_off);
765 a08582f4 Peter Maydell
        break;
766 a08582f4 Peter Maydell
    case MO_32:
767 a08582f4 Peter Maydell
    case MO_32|MO_SIGN:
768 a08582f4 Peter Maydell
        tcg_gen_ld_i32(tcg_dest, cpu_env, vect_off);
769 a08582f4 Peter Maydell
        break;
770 a08582f4 Peter Maydell
    default:
771 a08582f4 Peter Maydell
        g_assert_not_reached();
772 a08582f4 Peter Maydell
    }
773 a08582f4 Peter Maydell
}
774 a08582f4 Peter Maydell
775 72430bf5 Alex Bennée
/* Set value of an element within a vector register */
776 72430bf5 Alex Bennée
static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
777 72430bf5 Alex Bennée
                              int element, TCGMemOp memop)
778 72430bf5 Alex Bennée
{
779 72430bf5 Alex Bennée
    int vect_off = vec_reg_offset(destidx, element, memop & MO_SIZE);
780 72430bf5 Alex Bennée
    switch (memop) {
781 72430bf5 Alex Bennée
    case MO_8:
782 72430bf5 Alex Bennée
        tcg_gen_st8_i64(tcg_src, cpu_env, vect_off);
783 72430bf5 Alex Bennée
        break;
784 72430bf5 Alex Bennée
    case MO_16:
785 72430bf5 Alex Bennée
        tcg_gen_st16_i64(tcg_src, cpu_env, vect_off);
786 72430bf5 Alex Bennée
        break;
787 72430bf5 Alex Bennée
    case MO_32:
788 72430bf5 Alex Bennée
        tcg_gen_st32_i64(tcg_src, cpu_env, vect_off);
789 72430bf5 Alex Bennée
        break;
790 72430bf5 Alex Bennée
    case MO_64:
791 72430bf5 Alex Bennée
        tcg_gen_st_i64(tcg_src, cpu_env, vect_off);
792 72430bf5 Alex Bennée
        break;
793 72430bf5 Alex Bennée
    default:
794 72430bf5 Alex Bennée
        g_assert_not_reached();
795 72430bf5 Alex Bennée
    }
796 72430bf5 Alex Bennée
}
797 72430bf5 Alex Bennée
798 1f8a73af Peter Maydell
static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src,
799 1f8a73af Peter Maydell
                                  int destidx, int element, TCGMemOp memop)
800 1f8a73af Peter Maydell
{
801 1f8a73af Peter Maydell
    int vect_off = vec_reg_offset(destidx, element, memop & MO_SIZE);
802 1f8a73af Peter Maydell
    switch (memop) {
803 1f8a73af Peter Maydell
    case MO_8:
804 1f8a73af Peter Maydell
        tcg_gen_st8_i32(tcg_src, cpu_env, vect_off);
805 1f8a73af Peter Maydell
        break;
806 1f8a73af Peter Maydell
    case MO_16:
807 1f8a73af Peter Maydell
        tcg_gen_st16_i32(tcg_src, cpu_env, vect_off);
808 1f8a73af Peter Maydell
        break;
809 1f8a73af Peter Maydell
    case MO_32:
810 1f8a73af Peter Maydell
        tcg_gen_st_i32(tcg_src, cpu_env, vect_off);
811 1f8a73af Peter Maydell
        break;
812 1f8a73af Peter Maydell
    default:
813 1f8a73af Peter Maydell
        g_assert_not_reached();
814 1f8a73af Peter Maydell
    }
815 1f8a73af Peter Maydell
}
816 1f8a73af Peter Maydell
817 72430bf5 Alex Bennée
/* Clear the high 64 bits of a 128 bit vector (in general non-quad
818 72430bf5 Alex Bennée
 * vector ops all need to do this).
819 72430bf5 Alex Bennée
 */
820 72430bf5 Alex Bennée
static void clear_vec_high(DisasContext *s, int rd)
821 72430bf5 Alex Bennée
{
822 72430bf5 Alex Bennée
    TCGv_i64 tcg_zero = tcg_const_i64(0);
823 72430bf5 Alex Bennée
824 72430bf5 Alex Bennée
    write_vec_element(s, tcg_zero, rd, 1, MO_64);
825 72430bf5 Alex Bennée
    tcg_temp_free_i64(tcg_zero);
826 72430bf5 Alex Bennée
}
827 72430bf5 Alex Bennée
828 72430bf5 Alex Bennée
/* Store from vector register to memory */
829 72430bf5 Alex Bennée
static void do_vec_st(DisasContext *s, int srcidx, int element,
830 72430bf5 Alex Bennée
                      TCGv_i64 tcg_addr, int size)
831 72430bf5 Alex Bennée
{
832 72430bf5 Alex Bennée
    TCGMemOp memop = MO_TE + size;
833 72430bf5 Alex Bennée
    TCGv_i64 tcg_tmp = tcg_temp_new_i64();
834 72430bf5 Alex Bennée
835 72430bf5 Alex Bennée
    read_vec_element(s, tcg_tmp, srcidx, element, size);
836 72430bf5 Alex Bennée
    tcg_gen_qemu_st_i64(tcg_tmp, tcg_addr, get_mem_index(s), memop);
837 72430bf5 Alex Bennée
838 72430bf5 Alex Bennée
    tcg_temp_free_i64(tcg_tmp);
839 72430bf5 Alex Bennée
}
840 72430bf5 Alex Bennée
841 72430bf5 Alex Bennée
/* Load from memory to vector register */
842 72430bf5 Alex Bennée
static void do_vec_ld(DisasContext *s, int destidx, int element,
843 72430bf5 Alex Bennée
                      TCGv_i64 tcg_addr, int size)
844 72430bf5 Alex Bennée
{
845 72430bf5 Alex Bennée
    TCGMemOp memop = MO_TE + size;
846 72430bf5 Alex Bennée
    TCGv_i64 tcg_tmp = tcg_temp_new_i64();
847 72430bf5 Alex Bennée
848 72430bf5 Alex Bennée
    tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr, get_mem_index(s), memop);
849 72430bf5 Alex Bennée
    write_vec_element(s, tcg_tmp, destidx, element, size);
850 72430bf5 Alex Bennée
851 72430bf5 Alex Bennée
    tcg_temp_free_i64(tcg_tmp);
852 72430bf5 Alex Bennée
}
853 72430bf5 Alex Bennée
854 72430bf5 Alex Bennée
/*
855 229b7a05 Alex Bennée
 * This utility function is for doing register extension with an
856 229b7a05 Alex Bennée
 * optional shift. You will likely want to pass a temporary for the
857 229b7a05 Alex Bennée
 * destination register. See DecodeRegExtend() in the ARM ARM.
858 229b7a05 Alex Bennée
 */
859 229b7a05 Alex Bennée
static void ext_and_shift_reg(TCGv_i64 tcg_out, TCGv_i64 tcg_in,
860 229b7a05 Alex Bennée
                              int option, unsigned int shift)
861 229b7a05 Alex Bennée
{
862 229b7a05 Alex Bennée
    int extsize = extract32(option, 0, 2);
863 229b7a05 Alex Bennée
    bool is_signed = extract32(option, 2, 1);
864 229b7a05 Alex Bennée
865 229b7a05 Alex Bennée
    if (is_signed) {
866 229b7a05 Alex Bennée
        switch (extsize) {
867 229b7a05 Alex Bennée
        case 0:
868 229b7a05 Alex Bennée
            tcg_gen_ext8s_i64(tcg_out, tcg_in);
869 229b7a05 Alex Bennée
            break;
870 229b7a05 Alex Bennée
        case 1:
871 229b7a05 Alex Bennée
            tcg_gen_ext16s_i64(tcg_out, tcg_in);
872 229b7a05 Alex Bennée
            break;
873 229b7a05 Alex Bennée
        case 2:
874 229b7a05 Alex Bennée
            tcg_gen_ext32s_i64(tcg_out, tcg_in);
875 229b7a05 Alex Bennée
            break;
876 229b7a05 Alex Bennée
        case 3:
877 229b7a05 Alex Bennée
            tcg_gen_mov_i64(tcg_out, tcg_in);
878 229b7a05 Alex Bennée
            break;
879 229b7a05 Alex Bennée
        }
880 229b7a05 Alex Bennée
    } else {
881 229b7a05 Alex Bennée
        switch (extsize) {
882 229b7a05 Alex Bennée
        case 0:
883 229b7a05 Alex Bennée
            tcg_gen_ext8u_i64(tcg_out, tcg_in);
884 229b7a05 Alex Bennée
            break;
885 229b7a05 Alex Bennée
        case 1:
886 229b7a05 Alex Bennée
            tcg_gen_ext16u_i64(tcg_out, tcg_in);
887 229b7a05 Alex Bennée
            break;
888 229b7a05 Alex Bennée
        case 2:
889 229b7a05 Alex Bennée
            tcg_gen_ext32u_i64(tcg_out, tcg_in);
890 229b7a05 Alex Bennée
            break;
891 229b7a05 Alex Bennée
        case 3:
892 229b7a05 Alex Bennée
            tcg_gen_mov_i64(tcg_out, tcg_in);
893 229b7a05 Alex Bennée
            break;
894 229b7a05 Alex Bennée
        }
895 229b7a05 Alex Bennée
    }
896 229b7a05 Alex Bennée
897 229b7a05 Alex Bennée
    if (shift) {
898 229b7a05 Alex Bennée
        tcg_gen_shli_i64(tcg_out, tcg_out, shift);
899 229b7a05 Alex Bennée
    }
900 229b7a05 Alex Bennée
}
901 229b7a05 Alex Bennée
902 4a08d475 Peter Maydell
static inline void gen_check_sp_alignment(DisasContext *s)
903 4a08d475 Peter Maydell
{
904 4a08d475 Peter Maydell
    /* The AArch64 architecture mandates that (if enabled via PSTATE
905 4a08d475 Peter Maydell
     * or SCTLR bits) there is a check that SP is 16-aligned on every
906 4a08d475 Peter Maydell
     * SP-relative load or store (with an exception generated if it is not).
907 4a08d475 Peter Maydell
     * In line with general QEMU practice regarding misaligned accesses,
908 4a08d475 Peter Maydell
     * we omit these checks for the sake of guest program performance.
909 4a08d475 Peter Maydell
     * This function is provided as a hook so we can more easily add these
910 4a08d475 Peter Maydell
     * checks in future (possibly as a "favour catching guest program bugs
911 4a08d475 Peter Maydell
     * over speed" user selectable option).
912 4a08d475 Peter Maydell
     */
913 4a08d475 Peter Maydell
}
914 4a08d475 Peter Maydell
915 4a08d475 Peter Maydell
/*
916 384b26fb Alex Bennée
 * This provides a simple table based table lookup decoder. It is
917 384b26fb Alex Bennée
 * intended to be used when the relevant bits for decode are too
918 384b26fb Alex Bennée
 * awkwardly placed and switch/if based logic would be confusing and
919 384b26fb Alex Bennée
 * deeply nested. Since it's a linear search through the table, tables
920 384b26fb Alex Bennée
 * should be kept small.
921 384b26fb Alex Bennée
 *
922 384b26fb Alex Bennée
 * It returns the first handler where insn & mask == pattern, or
923 384b26fb Alex Bennée
 * NULL if there is no match.
924 384b26fb Alex Bennée
 * The table is terminated by an empty mask (i.e. 0)
925 384b26fb Alex Bennée
 */
926 384b26fb Alex Bennée
static inline AArch64DecodeFn *lookup_disas_fn(const AArch64DecodeTable *table,
927 384b26fb Alex Bennée
                                               uint32_t insn)
928 384b26fb Alex Bennée
{
929 384b26fb Alex Bennée
    const AArch64DecodeTable *tptr = table;
930 384b26fb Alex Bennée
931 384b26fb Alex Bennée
    while (tptr->mask) {
932 384b26fb Alex Bennée
        if ((insn & tptr->mask) == tptr->pattern) {
933 384b26fb Alex Bennée
            return tptr->disas_fn;
934 384b26fb Alex Bennée
        }
935 384b26fb Alex Bennée
        tptr++;
936 384b26fb Alex Bennée
    }
937 384b26fb Alex Bennée
    return NULL;
938 384b26fb Alex Bennée
}
939 384b26fb Alex Bennée
940 384b26fb Alex Bennée
/*
941 ad7ee8a2 Claudio Fontana
 * the instruction disassembly implemented here matches
942 ad7ee8a2 Claudio Fontana
 * the instruction encoding classifications in chapter 3 (C3)
943 ad7ee8a2 Claudio Fontana
 * of the ARM Architecture Reference Manual (DDI0487A_a)
944 ad7ee8a2 Claudio Fontana
 */
945 ad7ee8a2 Claudio Fontana
946 11e169de Alexander Graf
/* C3.2.7 Unconditional branch (immediate)
947 11e169de Alexander Graf
 *   31  30       26 25                                  0
948 11e169de Alexander Graf
 * +----+-----------+-------------------------------------+
949 11e169de Alexander Graf
 * | op | 0 0 1 0 1 |                 imm26               |
950 11e169de Alexander Graf
 * +----+-----------+-------------------------------------+
951 11e169de Alexander Graf
 */
952 ad7ee8a2 Claudio Fontana
static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
953 ad7ee8a2 Claudio Fontana
{
954 11e169de Alexander Graf
    uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
955 11e169de Alexander Graf
956 11e169de Alexander Graf
    if (insn & (1 << 31)) {
957 11e169de Alexander Graf
        /* C5.6.26 BL Branch with link */
958 11e169de Alexander Graf
        tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
959 11e169de Alexander Graf
    }
960 11e169de Alexander Graf
961 11e169de Alexander Graf
    /* C5.6.20 B Branch / C5.6.26 BL Branch with link */
962 11e169de Alexander Graf
    gen_goto_tb(s, 0, addr);
963 ad7ee8a2 Claudio Fontana
}
964 ad7ee8a2 Claudio Fontana
965 60e53388 Alexander Graf
/* C3.2.1 Compare & branch (immediate)
966 60e53388 Alexander Graf
 *   31  30         25  24  23                  5 4      0
967 60e53388 Alexander Graf
 * +----+-------------+----+---------------------+--------+
968 60e53388 Alexander Graf
 * | sf | 0 1 1 0 1 0 | op |         imm19       |   Rt   |
969 60e53388 Alexander Graf
 * +----+-------------+----+---------------------+--------+
970 60e53388 Alexander Graf
 */
971 ad7ee8a2 Claudio Fontana
static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
972 ad7ee8a2 Claudio Fontana
{
973 60e53388 Alexander Graf
    unsigned int sf, op, rt;
974 60e53388 Alexander Graf
    uint64_t addr;
975 60e53388 Alexander Graf
    int label_match;
976 60e53388 Alexander Graf
    TCGv_i64 tcg_cmp;
977 60e53388 Alexander Graf
978 60e53388 Alexander Graf
    sf = extract32(insn, 31, 1);
979 60e53388 Alexander Graf
    op = extract32(insn, 24, 1); /* 0: CBZ; 1: CBNZ */
980 60e53388 Alexander Graf
    rt = extract32(insn, 0, 5);
981 60e53388 Alexander Graf
    addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
982 60e53388 Alexander Graf
983 60e53388 Alexander Graf
    tcg_cmp = read_cpu_reg(s, rt, sf);
984 60e53388 Alexander Graf
    label_match = gen_new_label();
985 60e53388 Alexander Graf
986 60e53388 Alexander Graf
    tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
987 60e53388 Alexander Graf
                        tcg_cmp, 0, label_match);
988 60e53388 Alexander Graf
989 60e53388 Alexander Graf
    gen_goto_tb(s, 0, s->pc);
990 60e53388 Alexander Graf
    gen_set_label(label_match);
991 60e53388 Alexander Graf
    gen_goto_tb(s, 1, addr);
992 ad7ee8a2 Claudio Fontana
}
993 ad7ee8a2 Claudio Fontana
994 db0f7958 Alexander Graf
/* C3.2.5 Test & branch (immediate)
995 db0f7958 Alexander Graf
 *   31  30         25  24  23   19 18          5 4    0
996 db0f7958 Alexander Graf
 * +----+-------------+----+-------+-------------+------+
997 db0f7958 Alexander Graf
 * | b5 | 0 1 1 0 1 1 | op |  b40  |    imm14    |  Rt  |
998 db0f7958 Alexander Graf
 * +----+-------------+----+-------+-------------+------+
999 db0f7958 Alexander Graf
 */
1000 ad7ee8a2 Claudio Fontana
static void disas_test_b_imm(DisasContext *s, uint32_t insn)
1001 ad7ee8a2 Claudio Fontana
{
1002 db0f7958 Alexander Graf
    unsigned int bit_pos, op, rt;
1003 db0f7958 Alexander Graf
    uint64_t addr;
1004 db0f7958 Alexander Graf
    int label_match;
1005 db0f7958 Alexander Graf
    TCGv_i64 tcg_cmp;
1006 db0f7958 Alexander Graf
1007 db0f7958 Alexander Graf
    bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
1008 db0f7958 Alexander Graf
    op = extract32(insn, 24, 1); /* 0: TBZ; 1: TBNZ */
1009 db0f7958 Alexander Graf
    addr = s->pc + sextract32(insn, 5, 14) * 4 - 4;
1010 db0f7958 Alexander Graf
    rt = extract32(insn, 0, 5);
1011 db0f7958 Alexander Graf
1012 db0f7958 Alexander Graf
    tcg_cmp = tcg_temp_new_i64();
1013 db0f7958 Alexander Graf
    tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, rt), (1ULL << bit_pos));
1014 db0f7958 Alexander Graf
    label_match = gen_new_label();
1015 db0f7958 Alexander Graf
    tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
1016 db0f7958 Alexander Graf
                        tcg_cmp, 0, label_match);
1017 db0f7958 Alexander Graf
    tcg_temp_free_i64(tcg_cmp);
1018 db0f7958 Alexander Graf
    gen_goto_tb(s, 0, s->pc);
1019 db0f7958 Alexander Graf
    gen_set_label(label_match);
1020 db0f7958 Alexander Graf
    gen_goto_tb(s, 1, addr);
1021 ad7ee8a2 Claudio Fontana
}
1022 ad7ee8a2 Claudio Fontana
1023 39fb730a Alexander Graf
/* C3.2.2 / C5.6.19 Conditional branch (immediate)
1024 39fb730a Alexander Graf
 *  31           25  24  23                  5   4  3    0
1025 39fb730a Alexander Graf
 * +---------------+----+---------------------+----+------+
1026 39fb730a Alexander Graf
 * | 0 1 0 1 0 1 0 | o1 |         imm19       | o0 | cond |
1027 39fb730a Alexander Graf
 * +---------------+----+---------------------+----+------+
1028 39fb730a Alexander Graf
 */
1029 ad7ee8a2 Claudio Fontana
static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
1030 ad7ee8a2 Claudio Fontana
{
1031 39fb730a Alexander Graf
    unsigned int cond;
1032 39fb730a Alexander Graf
    uint64_t addr;
1033 39fb730a Alexander Graf
1034 39fb730a Alexander Graf
    if ((insn & (1 << 4)) || (insn & (1 << 24))) {
1035 39fb730a Alexander Graf
        unallocated_encoding(s);
1036 39fb730a Alexander Graf
        return;
1037 39fb730a Alexander Graf
    }
1038 39fb730a Alexander Graf
    addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
1039 39fb730a Alexander Graf
    cond = extract32(insn, 0, 4);
1040 39fb730a Alexander Graf
1041 39fb730a Alexander Graf
    if (cond < 0x0e) {
1042 39fb730a Alexander Graf
        /* genuinely conditional branches */
1043 39fb730a Alexander Graf
        int label_match = gen_new_label();
1044 39fb730a Alexander Graf
        arm_gen_test_cc(cond, label_match);
1045 39fb730a Alexander Graf
        gen_goto_tb(s, 0, s->pc);
1046 39fb730a Alexander Graf
        gen_set_label(label_match);
1047 39fb730a Alexander Graf
        gen_goto_tb(s, 1, addr);
1048 39fb730a Alexander Graf
    } else {
1049 39fb730a Alexander Graf
        /* 0xe and 0xf are both "always" conditions */
1050 39fb730a Alexander Graf
        gen_goto_tb(s, 0, addr);
1051 39fb730a Alexander Graf
    }
1052 ad7ee8a2 Claudio Fontana
}
1053 ad7ee8a2 Claudio Fontana
1054 87462e0f Claudio Fontana
/* C5.6.68 HINT */
1055 87462e0f Claudio Fontana
static void handle_hint(DisasContext *s, uint32_t insn,
1056 87462e0f Claudio Fontana
                        unsigned int op1, unsigned int op2, unsigned int crm)
1057 87462e0f Claudio Fontana
{
1058 87462e0f Claudio Fontana
    unsigned int selector = crm << 3 | op2;
1059 87462e0f Claudio Fontana
1060 87462e0f Claudio Fontana
    if (op1 != 3) {
1061 87462e0f Claudio Fontana
        unallocated_encoding(s);
1062 87462e0f Claudio Fontana
        return;
1063 87462e0f Claudio Fontana
    }
1064 87462e0f Claudio Fontana
1065 87462e0f Claudio Fontana
    switch (selector) {
1066 87462e0f Claudio Fontana
    case 0: /* NOP */
1067 87462e0f Claudio Fontana
        return;
1068 87462e0f Claudio Fontana
    case 1: /* YIELD */
1069 87462e0f Claudio Fontana
    case 2: /* WFE */
1070 87462e0f Claudio Fontana
    case 3: /* WFI */
1071 87462e0f Claudio Fontana
    case 4: /* SEV */
1072 87462e0f Claudio Fontana
    case 5: /* SEVL */
1073 87462e0f Claudio Fontana
        /* we treat all as NOP at least for now */
1074 87462e0f Claudio Fontana
        return;
1075 87462e0f Claudio Fontana
    default:
1076 87462e0f Claudio Fontana
        /* default specified as NOP equivalent */
1077 87462e0f Claudio Fontana
        return;
1078 87462e0f Claudio Fontana
    }
1079 87462e0f Claudio Fontana
}
1080 87462e0f Claudio Fontana
1081 fa2ef212 Michael Matz
static void gen_clrex(DisasContext *s, uint32_t insn)
1082 fa2ef212 Michael Matz
{
1083 fa2ef212 Michael Matz
    tcg_gen_movi_i64(cpu_exclusive_addr, -1);
1084 fa2ef212 Michael Matz
}
1085 fa2ef212 Michael Matz
1086 87462e0f Claudio Fontana
/* CLREX, DSB, DMB, ISB */
1087 87462e0f Claudio Fontana
static void handle_sync(DisasContext *s, uint32_t insn,
1088 87462e0f Claudio Fontana
                        unsigned int op1, unsigned int op2, unsigned int crm)
1089 87462e0f Claudio Fontana
{
1090 87462e0f Claudio Fontana
    if (op1 != 3) {
1091 87462e0f Claudio Fontana
        unallocated_encoding(s);
1092 87462e0f Claudio Fontana
        return;
1093 87462e0f Claudio Fontana
    }
1094 87462e0f Claudio Fontana
1095 87462e0f Claudio Fontana
    switch (op2) {
1096 87462e0f Claudio Fontana
    case 2: /* CLREX */
1097 fa2ef212 Michael Matz
        gen_clrex(s, insn);
1098 87462e0f Claudio Fontana
        return;
1099 87462e0f Claudio Fontana
    case 4: /* DSB */
1100 87462e0f Claudio Fontana
    case 5: /* DMB */
1101 87462e0f Claudio Fontana
    case 6: /* ISB */
1102 87462e0f Claudio Fontana
        /* We don't emulate caches so barriers are no-ops */
1103 87462e0f Claudio Fontana
        return;
1104 87462e0f Claudio Fontana
    default:
1105 87462e0f Claudio Fontana
        unallocated_encoding(s);
1106 87462e0f Claudio Fontana
        return;
1107 87462e0f Claudio Fontana
    }
1108 87462e0f Claudio Fontana
}
1109 87462e0f Claudio Fontana
1110 87462e0f Claudio Fontana
/* C5.6.130 MSR (immediate) - move immediate to processor state field */
1111 87462e0f Claudio Fontana
static void handle_msr_i(DisasContext *s, uint32_t insn,
1112 87462e0f Claudio Fontana
                         unsigned int op1, unsigned int op2, unsigned int crm)
1113 87462e0f Claudio Fontana
{
1114 87462e0f Claudio Fontana
    unsupported_encoding(s, insn);
1115 87462e0f Claudio Fontana
}
1116 87462e0f Claudio Fontana
1117 b0d2b7d0 Peter Maydell
static void gen_get_nzcv(TCGv_i64 tcg_rt)
1118 b0d2b7d0 Peter Maydell
{
1119 b0d2b7d0 Peter Maydell
    TCGv_i32 tmp = tcg_temp_new_i32();
1120 b0d2b7d0 Peter Maydell
    TCGv_i32 nzcv = tcg_temp_new_i32();
1121 b0d2b7d0 Peter Maydell
1122 b0d2b7d0 Peter Maydell
    /* build bit 31, N */
1123 b0d2b7d0 Peter Maydell
    tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
1124 b0d2b7d0 Peter Maydell
    /* build bit 30, Z */
1125 b0d2b7d0 Peter Maydell
    tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
1126 b0d2b7d0 Peter Maydell
    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
1127 b0d2b7d0 Peter Maydell
    /* build bit 29, C */
1128 b0d2b7d0 Peter Maydell
    tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
1129 b0d2b7d0 Peter Maydell
    /* build bit 28, V */
1130 b0d2b7d0 Peter Maydell
    tcg_gen_shri_i32(tmp, cpu_VF, 31);
1131 b0d2b7d0 Peter Maydell
    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
1132 b0d2b7d0 Peter Maydell
    /* generate result */
1133 b0d2b7d0 Peter Maydell
    tcg_gen_extu_i32_i64(tcg_rt, nzcv);
1134 b0d2b7d0 Peter Maydell
1135 b0d2b7d0 Peter Maydell
    tcg_temp_free_i32(nzcv);
1136 b0d2b7d0 Peter Maydell
    tcg_temp_free_i32(tmp);
1137 b0d2b7d0 Peter Maydell
}
1138 b0d2b7d0 Peter Maydell
1139 b0d2b7d0 Peter Maydell
static void gen_set_nzcv(TCGv_i64 tcg_rt)
1140 b0d2b7d0 Peter Maydell
1141 b0d2b7d0 Peter Maydell
{
1142 b0d2b7d0 Peter Maydell
    TCGv_i32 nzcv = tcg_temp_new_i32();
1143 b0d2b7d0 Peter Maydell
1144 b0d2b7d0 Peter Maydell
    /* take NZCV from R[t] */
1145 b0d2b7d0 Peter Maydell
    tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
1146 b0d2b7d0 Peter Maydell
1147 b0d2b7d0 Peter Maydell
    /* bit 31, N */
1148 b0d2b7d0 Peter Maydell
    tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
1149 b0d2b7d0 Peter Maydell
    /* bit 30, Z */
1150 b0d2b7d0 Peter Maydell
    tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
1151 b0d2b7d0 Peter Maydell
    tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
1152 b0d2b7d0 Peter Maydell
    /* bit 29, C */
1153 b0d2b7d0 Peter Maydell
    tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
1154 b0d2b7d0 Peter Maydell
    tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
1155 b0d2b7d0 Peter Maydell
    /* bit 28, V */
1156 b0d2b7d0 Peter Maydell
    tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
1157 b0d2b7d0 Peter Maydell
    tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
1158 b0d2b7d0 Peter Maydell
    tcg_temp_free_i32(nzcv);
1159 b0d2b7d0 Peter Maydell
}
1160 b0d2b7d0 Peter Maydell
1161 fea50522 Peter Maydell
/* C5.6.129 MRS - move from system register
1162 fea50522 Peter Maydell
 * C5.6.131 MSR (register) - move to system register
1163 fea50522 Peter Maydell
 * C5.6.204 SYS
1164 fea50522 Peter Maydell
 * C5.6.205 SYSL
1165 fea50522 Peter Maydell
 * These are all essentially the same insn in 'read' and 'write'
1166 fea50522 Peter Maydell
 * versions, with varying op0 fields.
1167 fea50522 Peter Maydell
 */
1168 fea50522 Peter Maydell
static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
1169 fea50522 Peter Maydell
                       unsigned int op0, unsigned int op1, unsigned int op2,
1170 87462e0f Claudio Fontana
                       unsigned int crn, unsigned int crm, unsigned int rt)
1171 87462e0f Claudio Fontana
{
1172 fea50522 Peter Maydell
    const ARMCPRegInfo *ri;
1173 fea50522 Peter Maydell
    TCGv_i64 tcg_rt;
1174 87462e0f Claudio Fontana
1175 fea50522 Peter Maydell
    ri = get_arm_cp_reginfo(s->cp_regs,
1176 fea50522 Peter Maydell
                            ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
1177 fea50522 Peter Maydell
                                               crn, crm, op0, op1, op2));
1178 87462e0f Claudio Fontana
1179 fea50522 Peter Maydell
    if (!ri) {
1180 626187d8 Peter Maydell
        /* Unknown register; this might be a guest error or a QEMU
1181 626187d8 Peter Maydell
         * unimplemented feature.
1182 626187d8 Peter Maydell
         */
1183 626187d8 Peter Maydell
        qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch64 "
1184 626187d8 Peter Maydell
                      "system register op0:%d op1:%d crn:%d crm:%d op2:%d\n",
1185 626187d8 Peter Maydell
                      isread ? "read" : "write", op0, op1, crn, crm, op2);
1186 fea50522 Peter Maydell
        unallocated_encoding(s);
1187 fea50522 Peter Maydell
        return;
1188 fea50522 Peter Maydell
    }
1189 fea50522 Peter Maydell
1190 fea50522 Peter Maydell
    /* Check access permissions */
1191 fea50522 Peter Maydell
    if (!cp_access_ok(s->current_pl, ri, isread)) {
1192 fea50522 Peter Maydell
        unallocated_encoding(s);
1193 fea50522 Peter Maydell
        return;
1194 fea50522 Peter Maydell
    }
1195 fea50522 Peter Maydell
1196 fea50522 Peter Maydell
    /* Handle special cases first */
1197 fea50522 Peter Maydell
    switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
1198 fea50522 Peter Maydell
    case ARM_CP_NOP:
1199 fea50522 Peter Maydell
        return;
1200 b0d2b7d0 Peter Maydell
    case ARM_CP_NZCV:
1201 b0d2b7d0 Peter Maydell
        tcg_rt = cpu_reg(s, rt);
1202 b0d2b7d0 Peter Maydell
        if (isread) {
1203 b0d2b7d0 Peter Maydell
            gen_get_nzcv(tcg_rt);
1204 b0d2b7d0 Peter Maydell
        } else {
1205 b0d2b7d0 Peter Maydell
            gen_set_nzcv(tcg_rt);
1206 b0d2b7d0 Peter Maydell
        }
1207 b0d2b7d0 Peter Maydell
        return;
1208 fea50522 Peter Maydell
    default:
1209 fea50522 Peter Maydell
        break;
1210 fea50522 Peter Maydell
    }
1211 fea50522 Peter Maydell
1212 fea50522 Peter Maydell
    if (use_icount && (ri->type & ARM_CP_IO)) {
1213 fea50522 Peter Maydell
        gen_io_start();
1214 fea50522 Peter Maydell
    }
1215 fea50522 Peter Maydell
1216 fea50522 Peter Maydell
    tcg_rt = cpu_reg(s, rt);
1217 fea50522 Peter Maydell
1218 fea50522 Peter Maydell
    if (isread) {
1219 fea50522 Peter Maydell
        if (ri->type & ARM_CP_CONST) {
1220 fea50522 Peter Maydell
            tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
1221 fea50522 Peter Maydell
        } else if (ri->readfn) {
1222 fea50522 Peter Maydell
            TCGv_ptr tmpptr;
1223 fea50522 Peter Maydell
            gen_a64_set_pc_im(s->pc - 4);
1224 fea50522 Peter Maydell
            tmpptr = tcg_const_ptr(ri);
1225 fea50522 Peter Maydell
            gen_helper_get_cp_reg64(tcg_rt, cpu_env, tmpptr);
1226 fea50522 Peter Maydell
            tcg_temp_free_ptr(tmpptr);
1227 fea50522 Peter Maydell
        } else {
1228 fea50522 Peter Maydell
            tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset);
1229 fea50522 Peter Maydell
        }
1230 fea50522 Peter Maydell
    } else {
1231 fea50522 Peter Maydell
        if (ri->type & ARM_CP_CONST) {
1232 fea50522 Peter Maydell
            /* If not forbidden by access permissions, treat as WI */
1233 fea50522 Peter Maydell
            return;
1234 fea50522 Peter Maydell
        } else if (ri->writefn) {
1235 fea50522 Peter Maydell
            TCGv_ptr tmpptr;
1236 fea50522 Peter Maydell
            gen_a64_set_pc_im(s->pc - 4);
1237 fea50522 Peter Maydell
            tmpptr = tcg_const_ptr(ri);
1238 fea50522 Peter Maydell
            gen_helper_set_cp_reg64(cpu_env, tmpptr, tcg_rt);
1239 fea50522 Peter Maydell
            tcg_temp_free_ptr(tmpptr);
1240 fea50522 Peter Maydell
        } else {
1241 fea50522 Peter Maydell
            tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset);
1242 fea50522 Peter Maydell
        }
1243 fea50522 Peter Maydell
    }
1244 fea50522 Peter Maydell
1245 fea50522 Peter Maydell
    if (use_icount && (ri->type & ARM_CP_IO)) {
1246 fea50522 Peter Maydell
        /* I/O operations must end the TB here (whether read or write) */
1247 fea50522 Peter Maydell
        gen_io_end();
1248 fea50522 Peter Maydell
        s->is_jmp = DISAS_UPDATE;
1249 fea50522 Peter Maydell
    } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
1250 fea50522 Peter Maydell
        /* We default to ending the TB on a coprocessor register write,
1251 fea50522 Peter Maydell
         * but allow this to be suppressed by the register definition
1252 fea50522 Peter Maydell
         * (usually only necessary to work around guest bugs).
1253 fea50522 Peter Maydell
         */
1254 fea50522 Peter Maydell
        s->is_jmp = DISAS_UPDATE;
1255 fea50522 Peter Maydell
    }
1256 ad7ee8a2 Claudio Fontana
}
1257 ad7ee8a2 Claudio Fontana
1258 87462e0f Claudio Fontana
/* C3.2.4 System
1259 87462e0f Claudio Fontana
 *  31                 22 21  20 19 18 16 15   12 11    8 7   5 4    0
1260 87462e0f Claudio Fontana
 * +---------------------+---+-----+-----+-------+-------+-----+------+
1261 87462e0f Claudio Fontana
 * | 1 1 0 1 0 1 0 1 0 0 | L | op0 | op1 |  CRn  |  CRm  | op2 |  Rt  |
1262 87462e0f Claudio Fontana
 * +---------------------+---+-----+-----+-------+-------+-----+------+
1263 87462e0f Claudio Fontana
 */
1264 87462e0f Claudio Fontana
static void disas_system(DisasContext *s, uint32_t insn)
1265 87462e0f Claudio Fontana
{
1266 87462e0f Claudio Fontana
    unsigned int l, op0, op1, crn, crm, op2, rt;
1267 87462e0f Claudio Fontana
    l = extract32(insn, 21, 1);
1268 87462e0f Claudio Fontana
    op0 = extract32(insn, 19, 2);
1269 87462e0f Claudio Fontana
    op1 = extract32(insn, 16, 3);
1270 87462e0f Claudio Fontana
    crn = extract32(insn, 12, 4);
1271 87462e0f Claudio Fontana
    crm = extract32(insn, 8, 4);
1272 87462e0f Claudio Fontana
    op2 = extract32(insn, 5, 3);
1273 87462e0f Claudio Fontana
    rt = extract32(insn, 0, 5);
1274 87462e0f Claudio Fontana
1275 87462e0f Claudio Fontana
    if (op0 == 0) {
1276 87462e0f Claudio Fontana
        if (l || rt != 31) {
1277 87462e0f Claudio Fontana
            unallocated_encoding(s);
1278 87462e0f Claudio Fontana
            return;
1279 87462e0f Claudio Fontana
        }
1280 87462e0f Claudio Fontana
        switch (crn) {
1281 87462e0f Claudio Fontana
        case 2: /* C5.6.68 HINT */
1282 87462e0f Claudio Fontana
            handle_hint(s, insn, op1, op2, crm);
1283 87462e0f Claudio Fontana
            break;
1284 87462e0f Claudio Fontana
        case 3: /* CLREX, DSB, DMB, ISB */
1285 87462e0f Claudio Fontana
            handle_sync(s, insn, op1, op2, crm);
1286 87462e0f Claudio Fontana
            break;
1287 87462e0f Claudio Fontana
        case 4: /* C5.6.130 MSR (immediate) */
1288 87462e0f Claudio Fontana
            handle_msr_i(s, insn, op1, op2, crm);
1289 87462e0f Claudio Fontana
            break;
1290 87462e0f Claudio Fontana
        default:
1291 87462e0f Claudio Fontana
            unallocated_encoding(s);
1292 87462e0f Claudio Fontana
            break;
1293 87462e0f Claudio Fontana
        }
1294 87462e0f Claudio Fontana
        return;
1295 87462e0f Claudio Fontana
    }
1296 fea50522 Peter Maydell
    handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);
1297 87462e0f Claudio Fontana
}
1298 87462e0f Claudio Fontana
1299 9618e809 Alexander Graf
/* C3.2.3 Exception generation
1300 9618e809 Alexander Graf
 *
1301 9618e809 Alexander Graf
 *  31             24 23 21 20                     5 4   2 1  0
1302 9618e809 Alexander Graf
 * +-----------------+-----+------------------------+-----+----+
1303 9618e809 Alexander Graf
 * | 1 1 0 1 0 1 0 0 | opc |          imm16         | op2 | LL |
1304 9618e809 Alexander Graf
 * +-----------------------+------------------------+----------+
1305 9618e809 Alexander Graf
 */
1306 ad7ee8a2 Claudio Fontana
static void disas_exc(DisasContext *s, uint32_t insn)
1307 ad7ee8a2 Claudio Fontana
{
1308 9618e809 Alexander Graf
    int opc = extract32(insn, 21, 3);
1309 9618e809 Alexander Graf
    int op2_ll = extract32(insn, 0, 5);
1310 9618e809 Alexander Graf
1311 9618e809 Alexander Graf
    switch (opc) {
1312 9618e809 Alexander Graf
    case 0:
1313 9618e809 Alexander Graf
        /* SVC, HVC, SMC; since we don't support the Virtualization
1314 9618e809 Alexander Graf
         * or TrustZone extensions these all UNDEF except SVC.
1315 9618e809 Alexander Graf
         */
1316 9618e809 Alexander Graf
        if (op2_ll != 1) {
1317 9618e809 Alexander Graf
            unallocated_encoding(s);
1318 9618e809 Alexander Graf
            break;
1319 9618e809 Alexander Graf
        }
1320 9618e809 Alexander Graf
        gen_exception_insn(s, 0, EXCP_SWI);
1321 9618e809 Alexander Graf
        break;
1322 9618e809 Alexander Graf
    case 1:
1323 9618e809 Alexander Graf
        if (op2_ll != 0) {
1324 9618e809 Alexander Graf
            unallocated_encoding(s);
1325 9618e809 Alexander Graf
            break;
1326 9618e809 Alexander Graf
        }
1327 9618e809 Alexander Graf
        /* BRK */
1328 9618e809 Alexander Graf
        gen_exception_insn(s, 0, EXCP_BKPT);
1329 9618e809 Alexander Graf
        break;
1330 9618e809 Alexander Graf
    case 2:
1331 9618e809 Alexander Graf
        if (op2_ll != 0) {
1332 9618e809 Alexander Graf
            unallocated_encoding(s);
1333 9618e809 Alexander Graf
            break;
1334 9618e809 Alexander Graf
        }
1335 9618e809 Alexander Graf
        /* HLT */
1336 9618e809 Alexander Graf
        unsupported_encoding(s, insn);
1337 9618e809 Alexander Graf
        break;
1338 9618e809 Alexander Graf
    case 5:
1339 9618e809 Alexander Graf
        if (op2_ll < 1 || op2_ll > 3) {
1340 9618e809 Alexander Graf
            unallocated_encoding(s);
1341 9618e809 Alexander Graf
            break;
1342 9618e809 Alexander Graf
        }
1343 9618e809 Alexander Graf
        /* DCPS1, DCPS2, DCPS3 */
1344 9618e809 Alexander Graf
        unsupported_encoding(s, insn);
1345 9618e809 Alexander Graf
        break;
1346 9618e809 Alexander Graf
    default:
1347 9618e809 Alexander Graf
        unallocated_encoding(s);
1348 9618e809 Alexander Graf
        break;
1349 9618e809 Alexander Graf
    }
1350 ad7ee8a2 Claudio Fontana
}
1351 ad7ee8a2 Claudio Fontana
1352 b001c8c3 Alexander Graf
/* C3.2.7 Unconditional branch (register)
1353 b001c8c3 Alexander Graf
 *  31           25 24   21 20   16 15   10 9    5 4     0
1354 b001c8c3 Alexander Graf
 * +---------------+-------+-------+-------+------+-------+
1355 b001c8c3 Alexander Graf
 * | 1 1 0 1 0 1 1 |  opc  |  op2  |  op3  |  Rn  |  op4  |
1356 b001c8c3 Alexander Graf
 * +---------------+-------+-------+-------+------+-------+
1357 b001c8c3 Alexander Graf
 */
1358 ad7ee8a2 Claudio Fontana
static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
1359 ad7ee8a2 Claudio Fontana
{
1360 b001c8c3 Alexander Graf
    unsigned int opc, op2, op3, rn, op4;
1361 b001c8c3 Alexander Graf
1362 b001c8c3 Alexander Graf
    opc = extract32(insn, 21, 4);
1363 b001c8c3 Alexander Graf
    op2 = extract32(insn, 16, 5);
1364 b001c8c3 Alexander Graf
    op3 = extract32(insn, 10, 6);
1365 b001c8c3 Alexander Graf
    rn = extract32(insn, 5, 5);
1366 b001c8c3 Alexander Graf
    op4 = extract32(insn, 0, 5);
1367 b001c8c3 Alexander Graf
1368 b001c8c3 Alexander Graf
    if (op4 != 0x0 || op3 != 0x0 || op2 != 0x1f) {
1369 b001c8c3 Alexander Graf
        unallocated_encoding(s);
1370 b001c8c3 Alexander Graf
        return;
1371 b001c8c3 Alexander Graf
    }
1372 b001c8c3 Alexander Graf
1373 b001c8c3 Alexander Graf
    switch (opc) {
1374 b001c8c3 Alexander Graf
    case 0: /* BR */
1375 b001c8c3 Alexander Graf
    case 2: /* RET */
1376 b001c8c3 Alexander Graf
        break;
1377 b001c8c3 Alexander Graf
    case 1: /* BLR */
1378 b001c8c3 Alexander Graf
        tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
1379 b001c8c3 Alexander Graf
        break;
1380 b001c8c3 Alexander Graf
    case 4: /* ERET */
1381 b001c8c3 Alexander Graf
    case 5: /* DRPS */
1382 b001c8c3 Alexander Graf
        if (rn != 0x1f) {
1383 b001c8c3 Alexander Graf
            unallocated_encoding(s);
1384 b001c8c3 Alexander Graf
        } else {
1385 b001c8c3 Alexander Graf
            unsupported_encoding(s, insn);
1386 b001c8c3 Alexander Graf
        }
1387 b001c8c3 Alexander Graf
        return;
1388 b001c8c3 Alexander Graf
    default:
1389 b001c8c3 Alexander Graf
        unallocated_encoding(s);
1390 b001c8c3 Alexander Graf
        return;
1391 b001c8c3 Alexander Graf
    }
1392 b001c8c3 Alexander Graf
1393 b001c8c3 Alexander Graf
    tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
1394 b001c8c3 Alexander Graf
    s->is_jmp = DISAS_JUMP;
1395 ad7ee8a2 Claudio Fontana
}
1396 ad7ee8a2 Claudio Fontana
1397 ad7ee8a2 Claudio Fontana
/* C3.2 Branches, exception generating and system instructions */
1398 ad7ee8a2 Claudio Fontana
static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
1399 ad7ee8a2 Claudio Fontana
{
1400 ad7ee8a2 Claudio Fontana
    switch (extract32(insn, 25, 7)) {
1401 ad7ee8a2 Claudio Fontana
    case 0x0a: case 0x0b:
1402 ad7ee8a2 Claudio Fontana
    case 0x4a: case 0x4b: /* Unconditional branch (immediate) */
1403 ad7ee8a2 Claudio Fontana
        disas_uncond_b_imm(s, insn);
1404 ad7ee8a2 Claudio Fontana
        break;
1405 ad7ee8a2 Claudio Fontana
    case 0x1a: case 0x5a: /* Compare & branch (immediate) */
1406 ad7ee8a2 Claudio Fontana
        disas_comp_b_imm(s, insn);
1407 ad7ee8a2 Claudio Fontana
        break;
1408 ad7ee8a2 Claudio Fontana
    case 0x1b: case 0x5b: /* Test & branch (immediate) */
1409 ad7ee8a2 Claudio Fontana
        disas_test_b_imm(s, insn);
1410 ad7ee8a2 Claudio Fontana
        break;
1411 ad7ee8a2 Claudio Fontana
    case 0x2a: /* Conditional branch (immediate) */
1412 ad7ee8a2 Claudio Fontana
        disas_cond_b_imm(s, insn);
1413 ad7ee8a2 Claudio Fontana
        break;
1414 ad7ee8a2 Claudio Fontana
    case 0x6a: /* Exception generation / System */
1415 ad7ee8a2 Claudio Fontana
        if (insn & (1 << 24)) {
1416 ad7ee8a2 Claudio Fontana
            disas_system(s, insn);
1417 ad7ee8a2 Claudio Fontana
        } else {
1418 ad7ee8a2 Claudio Fontana
            disas_exc(s, insn);
1419 ad7ee8a2 Claudio Fontana
        }
1420 ad7ee8a2 Claudio Fontana
        break;
1421 ad7ee8a2 Claudio Fontana
    case 0x6b: /* Unconditional branch (register) */
1422 ad7ee8a2 Claudio Fontana
        disas_uncond_b_reg(s, insn);
1423 ad7ee8a2 Claudio Fontana
        break;
1424 ad7ee8a2 Claudio Fontana
    default:
1425 ad7ee8a2 Claudio Fontana
        unallocated_encoding(s);
1426 ad7ee8a2 Claudio Fontana
        break;
1427 ad7ee8a2 Claudio Fontana
    }
1428 ad7ee8a2 Claudio Fontana
}
1429 ad7ee8a2 Claudio Fontana
1430 fa2ef212 Michael Matz
/*
1431 fa2ef212 Michael Matz
 * Load/Store exclusive instructions are implemented by remembering
1432 fa2ef212 Michael Matz
 * the value/address loaded, and seeing if these are the same
1433 fa2ef212 Michael Matz
 * when the store is performed. This is not actually the architecturally
1434 fa2ef212 Michael Matz
 * mandated semantics, but it works for typical guest code sequences
1435 fa2ef212 Michael Matz
 * and avoids having to monitor regular stores.
1436 fa2ef212 Michael Matz
 *
1437 fa2ef212 Michael Matz
 * In system emulation mode only one CPU will be running at once, so
1438 fa2ef212 Michael Matz
 * this sequence is effectively atomic.  In user emulation mode we
1439 fa2ef212 Michael Matz
 * throw an exception and handle the atomic operation elsewhere.
1440 fa2ef212 Michael Matz
 */
1441 fa2ef212 Michael Matz
static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
1442 fa2ef212 Michael Matz
                               TCGv_i64 addr, int size, bool is_pair)
1443 fa2ef212 Michael Matz
{
1444 fa2ef212 Michael Matz
    TCGv_i64 tmp = tcg_temp_new_i64();
1445 fa2ef212 Michael Matz
    TCGMemOp memop = MO_TE + size;
1446 fa2ef212 Michael Matz
1447 fa2ef212 Michael Matz
    g_assert(size <= 3);
1448 fa2ef212 Michael Matz
    tcg_gen_qemu_ld_i64(tmp, addr, get_mem_index(s), memop);
1449 fa2ef212 Michael Matz
1450 fa2ef212 Michael Matz
    if (is_pair) {
1451 fa2ef212 Michael Matz
        TCGv_i64 addr2 = tcg_temp_new_i64();
1452 fa2ef212 Michael Matz
        TCGv_i64 hitmp = tcg_temp_new_i64();
1453 fa2ef212 Michael Matz
1454 fa2ef212 Michael Matz
        g_assert(size >= 2);
1455 fa2ef212 Michael Matz
        tcg_gen_addi_i64(addr2, addr, 1 << size);
1456 fa2ef212 Michael Matz
        tcg_gen_qemu_ld_i64(hitmp, addr2, get_mem_index(s), memop);
1457 fa2ef212 Michael Matz
        tcg_temp_free_i64(addr2);
1458 fa2ef212 Michael Matz
        tcg_gen_mov_i64(cpu_exclusive_high, hitmp);
1459 fa2ef212 Michael Matz
        tcg_gen_mov_i64(cpu_reg(s, rt2), hitmp);
1460 fa2ef212 Michael Matz
        tcg_temp_free_i64(hitmp);
1461 fa2ef212 Michael Matz
    }
1462 fa2ef212 Michael Matz
1463 fa2ef212 Michael Matz
    tcg_gen_mov_i64(cpu_exclusive_val, tmp);
1464 fa2ef212 Michael Matz
    tcg_gen_mov_i64(cpu_reg(s, rt), tmp);
1465 fa2ef212 Michael Matz
1466 fa2ef212 Michael Matz
    tcg_temp_free_i64(tmp);
1467 fa2ef212 Michael Matz
    tcg_gen_mov_i64(cpu_exclusive_addr, addr);
1468 fa2ef212 Michael Matz
}
1469 fa2ef212 Michael Matz
1470 fa2ef212 Michael Matz
#ifdef CONFIG_USER_ONLY
1471 fa2ef212 Michael Matz
static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
1472 fa2ef212 Michael Matz
                                TCGv_i64 addr, int size, int is_pair)
1473 fa2ef212 Michael Matz
{
1474 fa2ef212 Michael Matz
    tcg_gen_mov_i64(cpu_exclusive_test, addr);
1475 fa2ef212 Michael Matz
    tcg_gen_movi_i32(cpu_exclusive_info,
1476 fa2ef212 Michael Matz
                     size | is_pair << 2 | (rd << 4) | (rt << 9) | (rt2 << 14));
1477 fa2ef212 Michael Matz
    gen_exception_insn(s, 4, EXCP_STREX);
1478 fa2ef212 Michael Matz
}
1479 fa2ef212 Michael Matz
#else
1480 fa2ef212 Michael Matz
static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
1481 fa2ef212 Michael Matz
                                TCGv_i64 addr, int size, int is_pair)
1482 fa2ef212 Michael Matz
{
1483 fa2ef212 Michael Matz
    qemu_log_mask(LOG_UNIMP,
1484 fa2ef212 Michael Matz
                  "%s:%d: system mode store_exclusive unsupported "
1485 fa2ef212 Michael Matz
                  "at pc=%016" PRIx64 "\n",
1486 fa2ef212 Michael Matz
                  __FILE__, __LINE__, s->pc - 4);
1487 fa2ef212 Michael Matz
}
1488 fa2ef212 Michael Matz
#endif
1489 fa2ef212 Michael Matz
1490 fa2ef212 Michael Matz
/* C3.3.6 Load/store exclusive
1491 fa2ef212 Michael Matz
 *
1492 fa2ef212 Michael Matz
 *  31 30 29         24  23  22   21  20  16  15  14   10 9    5 4    0
1493 fa2ef212 Michael Matz
 * +-----+-------------+----+---+----+------+----+-------+------+------+
1494 fa2ef212 Michael Matz
 * | sz  | 0 0 1 0 0 0 | o2 | L | o1 |  Rs  | o0 |  Rt2  |  Rn  | Rt   |
1495 fa2ef212 Michael Matz
 * +-----+-------------+----+---+----+------+----+-------+------+------+
1496 fa2ef212 Michael Matz
 *
1497 fa2ef212 Michael Matz
 *  sz: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64 bit
1498 fa2ef212 Michael Matz
 *   L: 0 -> store, 1 -> load
1499 fa2ef212 Michael Matz
 *  o2: 0 -> exclusive, 1 -> not
1500 fa2ef212 Michael Matz
 *  o1: 0 -> single register, 1 -> register pair
1501 fa2ef212 Michael Matz
 *  o0: 1 -> load-acquire/store-release, 0 -> not
1502 fa2ef212 Michael Matz
 *
1503 fa2ef212 Michael Matz
 *  o0 == 0 AND o2 == 1 is un-allocated
1504 fa2ef212 Michael Matz
 *  o1 == 1 is un-allocated except for 32 and 64 bit sizes
1505 fa2ef212 Michael Matz
 */
1506 ad7ee8a2 Claudio Fontana
static void disas_ldst_excl(DisasContext *s, uint32_t insn)
1507 ad7ee8a2 Claudio Fontana
{
1508 fa2ef212 Michael Matz
    int rt = extract32(insn, 0, 5);
1509 fa2ef212 Michael Matz
    int rn = extract32(insn, 5, 5);
1510 fa2ef212 Michael Matz
    int rt2 = extract32(insn, 10, 5);
1511 fa2ef212 Michael Matz
    int is_lasr = extract32(insn, 15, 1);
1512 fa2ef212 Michael Matz
    int rs = extract32(insn, 16, 5);
1513 fa2ef212 Michael Matz
    int is_pair = extract32(insn, 21, 1);
1514 fa2ef212 Michael Matz
    int is_store = !extract32(insn, 22, 1);
1515 fa2ef212 Michael Matz
    int is_excl = !extract32(insn, 23, 1);
1516 fa2ef212 Michael Matz
    int size = extract32(insn, 30, 2);
1517 fa2ef212 Michael Matz
    TCGv_i64 tcg_addr;
1518 fa2ef212 Michael Matz
1519 fa2ef212 Michael Matz
    if ((!is_excl && !is_lasr) ||
1520 fa2ef212 Michael Matz
        (is_pair && size < 2)) {
1521 fa2ef212 Michael Matz
        unallocated_encoding(s);
1522 fa2ef212 Michael Matz
        return;
1523 fa2ef212 Michael Matz
    }
1524 fa2ef212 Michael Matz
1525 fa2ef212 Michael Matz
    if (rn == 31) {
1526 fa2ef212 Michael Matz
        gen_check_sp_alignment(s);
1527 fa2ef212 Michael Matz
    }
1528 fa2ef212 Michael Matz
    tcg_addr = read_cpu_reg_sp(s, rn, 1);
1529 fa2ef212 Michael Matz
1530 fa2ef212 Michael Matz
    /* Note that since TCG is single threaded load-acquire/store-release
1531 fa2ef212 Michael Matz
     * semantics require no extra if (is_lasr) { ... } handling.
1532 fa2ef212 Michael Matz
     */
1533 fa2ef212 Michael Matz
1534 fa2ef212 Michael Matz
    if (is_excl) {
1535 fa2ef212 Michael Matz
        if (!is_store) {
1536 fa2ef212 Michael Matz
            gen_load_exclusive(s, rt, rt2, tcg_addr, size, is_pair);
1537 fa2ef212 Michael Matz
        } else {
1538 fa2ef212 Michael Matz
            gen_store_exclusive(s, rs, rt, rt2, tcg_addr, size, is_pair);
1539 fa2ef212 Michael Matz
        }
1540 fa2ef212 Michael Matz
    } else {
1541 fa2ef212 Michael Matz
        TCGv_i64 tcg_rt = cpu_reg(s, rt);
1542 fa2ef212 Michael Matz
        if (is_store) {
1543 fa2ef212 Michael Matz
            do_gpr_st(s, tcg_rt, tcg_addr, size);
1544 fa2ef212 Michael Matz
        } else {
1545 fa2ef212 Michael Matz
            do_gpr_ld(s, tcg_rt, tcg_addr, size, false, false);
1546 fa2ef212 Michael Matz
        }
1547 fa2ef212 Michael Matz
        if (is_pair) {
1548 fa2ef212 Michael Matz
            TCGv_i64 tcg_rt2 = cpu_reg(s, rt);
1549 fa2ef212 Michael Matz
            tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
1550 fa2ef212 Michael Matz
            if (is_store) {
1551 fa2ef212 Michael Matz
                do_gpr_st(s, tcg_rt2, tcg_addr, size);
1552 fa2ef212 Michael Matz
            } else {
1553 fa2ef212 Michael Matz
                do_gpr_ld(s, tcg_rt2, tcg_addr, size, false, false);
1554 fa2ef212 Michael Matz
            }
1555 fa2ef212 Michael Matz
        }
1556 fa2ef212 Michael Matz
    }
1557 ad7ee8a2 Claudio Fontana
}
1558 ad7ee8a2 Claudio Fontana
1559 32b64e86 Alexander Graf
/*
1560 32b64e86 Alexander Graf
 * C3.3.5 Load register (literal)
1561 32b64e86 Alexander Graf
 *
1562 32b64e86 Alexander Graf
 *  31 30 29   27  26 25 24 23                5 4     0
1563 32b64e86 Alexander Graf
 * +-----+-------+---+-----+-------------------+-------+
1564 32b64e86 Alexander Graf
 * | opc | 0 1 1 | V | 0 0 |     imm19         |  Rt   |
1565 32b64e86 Alexander Graf
 * +-----+-------+---+-----+-------------------+-------+
1566 32b64e86 Alexander Graf
 *
1567 32b64e86 Alexander Graf
 * V: 1 -> vector (simd/fp)
1568 32b64e86 Alexander Graf
 * opc (non-vector): 00 -> 32 bit, 01 -> 64 bit,
1569 32b64e86 Alexander Graf
 *                   10-> 32 bit signed, 11 -> prefetch
1570 32b64e86 Alexander Graf
 * opc (vector): 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit (11 unallocated)
1571 32b64e86 Alexander Graf
 */
1572 ad7ee8a2 Claudio Fontana
static void disas_ld_lit(DisasContext *s, uint32_t insn)
1573 ad7ee8a2 Claudio Fontana
{
1574 32b64e86 Alexander Graf
    int rt = extract32(insn, 0, 5);
1575 32b64e86 Alexander Graf
    int64_t imm = sextract32(insn, 5, 19) << 2;
1576 32b64e86 Alexander Graf
    bool is_vector = extract32(insn, 26, 1);
1577 32b64e86 Alexander Graf
    int opc = extract32(insn, 30, 2);
1578 32b64e86 Alexander Graf
    bool is_signed = false;
1579 32b64e86 Alexander Graf
    int size = 2;
1580 32b64e86 Alexander Graf
    TCGv_i64 tcg_rt, tcg_addr;
1581 32b64e86 Alexander Graf
1582 32b64e86 Alexander Graf
    if (is_vector) {
1583 32b64e86 Alexander Graf
        if (opc == 3) {
1584 32b64e86 Alexander Graf
            unallocated_encoding(s);
1585 32b64e86 Alexander Graf
            return;
1586 32b64e86 Alexander Graf
        }
1587 32b64e86 Alexander Graf
        size = 2 + opc;
1588 32b64e86 Alexander Graf
    } else {
1589 32b64e86 Alexander Graf
        if (opc == 3) {
1590 32b64e86 Alexander Graf
            /* PRFM (literal) : prefetch */
1591 32b64e86 Alexander Graf
            return;
1592 32b64e86 Alexander Graf
        }
1593 32b64e86 Alexander Graf
        size = 2 + extract32(opc, 0, 1);
1594 32b64e86 Alexander Graf
        is_signed = extract32(opc, 1, 1);
1595 32b64e86 Alexander Graf
    }
1596 32b64e86 Alexander Graf
1597 32b64e86 Alexander Graf
    tcg_rt = cpu_reg(s, rt);
1598 32b64e86 Alexander Graf
1599 32b64e86 Alexander Graf
    tcg_addr = tcg_const_i64((s->pc - 4) + imm);
1600 32b64e86 Alexander Graf
    if (is_vector) {
1601 32b64e86 Alexander Graf
        do_fp_ld(s, rt, tcg_addr, size);
1602 32b64e86 Alexander Graf
    } else {
1603 32b64e86 Alexander Graf
        do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false);
1604 32b64e86 Alexander Graf
    }
1605 32b64e86 Alexander Graf
    tcg_temp_free_i64(tcg_addr);
1606 ad7ee8a2 Claudio Fontana
}
1607 ad7ee8a2 Claudio Fontana
1608 4a08d475 Peter Maydell
/*
1609 4a08d475 Peter Maydell
 * C5.6.80 LDNP (Load Pair - non-temporal hint)
1610 4a08d475 Peter Maydell
 * C5.6.81 LDP (Load Pair - non vector)
1611 4a08d475 Peter Maydell
 * C5.6.82 LDPSW (Load Pair Signed Word - non vector)
1612 4a08d475 Peter Maydell
 * C5.6.176 STNP (Store Pair - non-temporal hint)
1613 4a08d475 Peter Maydell
 * C5.6.177 STP (Store Pair - non vector)
1614 4a08d475 Peter Maydell
 * C6.3.165 LDNP (Load Pair of SIMD&FP - non-temporal hint)
1615 4a08d475 Peter Maydell
 * C6.3.165 LDP (Load Pair of SIMD&FP)
1616 4a08d475 Peter Maydell
 * C6.3.284 STNP (Store Pair of SIMD&FP - non-temporal hint)
1617 4a08d475 Peter Maydell
 * C6.3.284 STP (Store Pair of SIMD&FP)
1618 4a08d475 Peter Maydell
 *
1619 4a08d475 Peter Maydell
 *  31 30 29   27  26  25 24   23  22 21   15 14   10 9    5 4    0
1620 4a08d475 Peter Maydell
 * +-----+-------+---+---+-------+---+-----------------------------+
1621 4a08d475 Peter Maydell
 * | opc | 1 0 1 | V | 0 | index | L |  imm7 |  Rt2  |  Rn  | Rt   |
1622 4a08d475 Peter Maydell
 * +-----+-------+---+---+-------+---+-------+-------+------+------+
1623 4a08d475 Peter Maydell
 *
1624 4a08d475 Peter Maydell
 * opc: LDP/STP/LDNP/STNP        00 -> 32 bit, 10 -> 64 bit
1625 4a08d475 Peter Maydell
 *      LDPSW                    01
1626 4a08d475 Peter Maydell
 *      LDP/STP/LDNP/STNP (SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit
1627 4a08d475 Peter Maydell
 *   V: 0 -> GPR, 1 -> Vector
1628 4a08d475 Peter Maydell
 * idx: 00 -> signed offset with non-temporal hint, 01 -> post-index,
1629 4a08d475 Peter Maydell
 *      10 -> signed offset, 11 -> pre-index
1630 4a08d475 Peter Maydell
 *   L: 0 -> Store 1 -> Load
1631 4a08d475 Peter Maydell
 *
1632 4a08d475 Peter Maydell
 * Rt, Rt2 = GPR or SIMD registers to be stored
1633 4a08d475 Peter Maydell
 * Rn = general purpose register containing address
1634 4a08d475 Peter Maydell
 * imm7 = signed offset (multiple of 4 or 8 depending on size)
1635 4a08d475 Peter Maydell
 */
1636 ad7ee8a2 Claudio Fontana
static void disas_ldst_pair(DisasContext *s, uint32_t insn)
1637 ad7ee8a2 Claudio Fontana
{
1638 4a08d475 Peter Maydell
    int rt = extract32(insn, 0, 5);
1639 4a08d475 Peter Maydell
    int rn = extract32(insn, 5, 5);
1640 4a08d475 Peter Maydell
    int rt2 = extract32(insn, 10, 5);
1641 4a08d475 Peter Maydell
    int64_t offset = sextract32(insn, 15, 7);
1642 4a08d475 Peter Maydell
    int index = extract32(insn, 23, 2);
1643 4a08d475 Peter Maydell
    bool is_vector = extract32(insn, 26, 1);
1644 4a08d475 Peter Maydell
    bool is_load = extract32(insn, 22, 1);
1645 4a08d475 Peter Maydell
    int opc = extract32(insn, 30, 2);
1646 4a08d475 Peter Maydell
1647 4a08d475 Peter Maydell
    bool is_signed = false;
1648 4a08d475 Peter Maydell
    bool postindex = false;
1649 4a08d475 Peter Maydell
    bool wback = false;
1650 4a08d475 Peter Maydell
1651 4a08d475 Peter Maydell
    TCGv_i64 tcg_addr; /* calculated address */
1652 4a08d475 Peter Maydell
    int size;
1653 4a08d475 Peter Maydell
1654 4a08d475 Peter Maydell
    if (opc == 3) {
1655 4a08d475 Peter Maydell
        unallocated_encoding(s);
1656 4a08d475 Peter Maydell
        return;
1657 4a08d475 Peter Maydell
    }
1658 4a08d475 Peter Maydell
1659 4a08d475 Peter Maydell
    if (is_vector) {
1660 4a08d475 Peter Maydell
        size = 2 + opc;
1661 4a08d475 Peter Maydell
    } else {
1662 4a08d475 Peter Maydell
        size = 2 + extract32(opc, 1, 1);
1663 4a08d475 Peter Maydell
        is_signed = extract32(opc, 0, 1);
1664 4a08d475 Peter Maydell
        if (!is_load && is_signed) {
1665 4a08d475 Peter Maydell
            unallocated_encoding(s);
1666 4a08d475 Peter Maydell
            return;
1667 4a08d475 Peter Maydell
        }
1668 4a08d475 Peter Maydell
    }
1669 4a08d475 Peter Maydell
1670 4a08d475 Peter Maydell
    switch (index) {
1671 4a08d475 Peter Maydell
    case 1: /* post-index */
1672 4a08d475 Peter Maydell
        postindex = true;
1673 4a08d475 Peter Maydell
        wback = true;
1674 4a08d475 Peter Maydell
        break;
1675 4a08d475 Peter Maydell
    case 0:
1676 4a08d475 Peter Maydell
        /* signed offset with "non-temporal" hint. Since we don't emulate
1677 4a08d475 Peter Maydell
         * caches we don't care about hints to the cache system about
1678 4a08d475 Peter Maydell
         * data access patterns, and handle this identically to plain
1679 4a08d475 Peter Maydell
         * signed offset.
1680 4a08d475 Peter Maydell
         */
1681 4a08d475 Peter Maydell
        if (is_signed) {
1682 4a08d475 Peter Maydell
            /* There is no non-temporal-hint version of LDPSW */
1683 4a08d475 Peter Maydell
            unallocated_encoding(s);
1684 4a08d475 Peter Maydell
            return;
1685 4a08d475 Peter Maydell
        }
1686 4a08d475 Peter Maydell
        postindex = false;
1687 4a08d475 Peter Maydell
        break;
1688 4a08d475 Peter Maydell
    case 2: /* signed offset, rn not updated */
1689 4a08d475 Peter Maydell
        postindex = false;
1690 4a08d475 Peter Maydell
        break;
1691 4a08d475 Peter Maydell
    case 3: /* pre-index */
1692 4a08d475 Peter Maydell
        postindex = false;
1693 4a08d475 Peter Maydell
        wback = true;
1694 4a08d475 Peter Maydell
        break;
1695 4a08d475 Peter Maydell
    }
1696 4a08d475 Peter Maydell
1697 4a08d475 Peter Maydell
    offset <<= size;
1698 4a08d475 Peter Maydell
1699 4a08d475 Peter Maydell
    if (rn == 31) {
1700 4a08d475 Peter Maydell
        gen_check_sp_alignment(s);
1701 4a08d475 Peter Maydell
    }
1702 4a08d475 Peter Maydell
1703 4a08d475 Peter Maydell
    tcg_addr = read_cpu_reg_sp(s, rn, 1);
1704 4a08d475 Peter Maydell
1705 4a08d475 Peter Maydell
    if (!postindex) {
1706 4a08d475 Peter Maydell
        tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
1707 4a08d475 Peter Maydell
    }
1708 4a08d475 Peter Maydell
1709 4a08d475 Peter Maydell
    if (is_vector) {
1710 4a08d475 Peter Maydell
        if (is_load) {
1711 4a08d475 Peter Maydell
            do_fp_ld(s, rt, tcg_addr, size);
1712 4a08d475 Peter Maydell
        } else {
1713 4a08d475 Peter Maydell
            do_fp_st(s, rt, tcg_addr, size);
1714 4a08d475 Peter Maydell
        }
1715 4a08d475 Peter Maydell
    } else {
1716 4a08d475 Peter Maydell
        TCGv_i64 tcg_rt = cpu_reg(s, rt);
1717 4a08d475 Peter Maydell
        if (is_load) {
1718 4a08d475 Peter Maydell
            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false);
1719 4a08d475 Peter Maydell
        } else {
1720 4a08d475 Peter Maydell
            do_gpr_st(s, tcg_rt, tcg_addr, size);
1721 4a08d475 Peter Maydell
        }
1722 4a08d475 Peter Maydell
    }
1723 4a08d475 Peter Maydell
    tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
1724 4a08d475 Peter Maydell
    if (is_vector) {
1725 4a08d475 Peter Maydell
        if (is_load) {
1726 4a08d475 Peter Maydell
            do_fp_ld(s, rt2, tcg_addr, size);
1727 4a08d475 Peter Maydell
        } else {
1728 4a08d475 Peter Maydell
            do_fp_st(s, rt2, tcg_addr, size);
1729 4a08d475 Peter Maydell
        }
1730 4a08d475 Peter Maydell
    } else {
1731 4a08d475 Peter Maydell
        TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
1732 4a08d475 Peter Maydell
        if (is_load) {
1733 4a08d475 Peter Maydell
            do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false);
1734 4a08d475 Peter Maydell
        } else {
1735 4a08d475 Peter Maydell
            do_gpr_st(s, tcg_rt2, tcg_addr, size);
1736 4a08d475 Peter Maydell
        }
1737 4a08d475 Peter Maydell
    }
1738 4a08d475 Peter Maydell
1739 4a08d475 Peter Maydell
    if (wback) {
1740 4a08d475 Peter Maydell
        if (postindex) {
1741 4a08d475 Peter Maydell
            tcg_gen_addi_i64(tcg_addr, tcg_addr, offset - (1 << size));
1742 4a08d475 Peter Maydell
        } else {
1743 4a08d475 Peter Maydell
            tcg_gen_subi_i64(tcg_addr, tcg_addr, 1 << size);
1744 4a08d475 Peter Maydell
        }
1745 4a08d475 Peter Maydell
        tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
1746 4a08d475 Peter Maydell
    }
1747 ad7ee8a2 Claudio Fontana
}
1748 ad7ee8a2 Claudio Fontana
1749 d5612f10 Alex Bennée
/*
1750 a5e94a9d Alex Bennée
 * C3.3.8 Load/store (immediate post-indexed)
1751 a5e94a9d Alex Bennée
 * C3.3.9 Load/store (immediate pre-indexed)
1752 a5e94a9d Alex Bennée
 * C3.3.12 Load/store (unscaled immediate)
1753 a5e94a9d Alex Bennée
 *
1754 a5e94a9d Alex Bennée
 * 31 30 29   27  26 25 24 23 22 21  20    12 11 10 9    5 4    0
1755 a5e94a9d Alex Bennée
 * +----+-------+---+-----+-----+---+--------+-----+------+------+
1756 a5e94a9d Alex Bennée
 * |size| 1 1 1 | V | 0 0 | opc | 0 |  imm9  | idx |  Rn  |  Rt  |
1757 a5e94a9d Alex Bennée
 * +----+-------+---+-----+-----+---+--------+-----+------+------+
1758 a5e94a9d Alex Bennée
 *
1759 a5e94a9d Alex Bennée
 * idx = 01 -> post-indexed, 11 pre-indexed, 00 unscaled imm. (no writeback)
1760 a5e94a9d Alex Bennée
 * V = 0 -> non-vector
1761 a5e94a9d Alex Bennée
 * size: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64bit
1762 a5e94a9d Alex Bennée
 * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
1763 a5e94a9d Alex Bennée
 */
1764 a5e94a9d Alex Bennée
static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn)
1765 a5e94a9d Alex Bennée
{
1766 a5e94a9d Alex Bennée
    int rt = extract32(insn, 0, 5);
1767 a5e94a9d Alex Bennée
    int rn = extract32(insn, 5, 5);
1768 a5e94a9d Alex Bennée
    int imm9 = sextract32(insn, 12, 9);
1769 a5e94a9d Alex Bennée
    int opc = extract32(insn, 22, 2);
1770 a5e94a9d Alex Bennée
    int size = extract32(insn, 30, 2);
1771 a5e94a9d Alex Bennée
    int idx = extract32(insn, 10, 2);
1772 a5e94a9d Alex Bennée
    bool is_signed = false;
1773 a5e94a9d Alex Bennée
    bool is_store = false;
1774 a5e94a9d Alex Bennée
    bool is_extended = false;
1775 a5e94a9d Alex Bennée
    bool is_vector = extract32(insn, 26, 1);
1776 a5e94a9d Alex Bennée
    bool post_index;
1777 a5e94a9d Alex Bennée
    bool writeback;
1778 a5e94a9d Alex Bennée
1779 a5e94a9d Alex Bennée
    TCGv_i64 tcg_addr;
1780 a5e94a9d Alex Bennée
1781 a5e94a9d Alex Bennée
    if (is_vector) {
1782 a5e94a9d Alex Bennée
        size |= (opc & 2) << 1;
1783 a5e94a9d Alex Bennée
        if (size > 4) {
1784 a5e94a9d Alex Bennée
            unallocated_encoding(s);
1785 a5e94a9d Alex Bennée
            return;
1786 a5e94a9d Alex Bennée
        }
1787 a5e94a9d Alex Bennée
        is_store = ((opc & 1) == 0);
1788 a5e94a9d Alex Bennée
    } else {
1789 a5e94a9d Alex Bennée
        if (size == 3 && opc == 2) {
1790 a5e94a9d Alex Bennée
            /* PRFM - prefetch */
1791 a5e94a9d Alex Bennée
            return;
1792 a5e94a9d Alex Bennée
        }
1793 a5e94a9d Alex Bennée
        if (opc == 3 && size > 1) {
1794 a5e94a9d Alex Bennée
            unallocated_encoding(s);
1795 a5e94a9d Alex Bennée
            return;
1796 a5e94a9d Alex Bennée
        }
1797 a5e94a9d Alex Bennée
        is_store = (opc == 0);
1798 a5e94a9d Alex Bennée
        is_signed = opc & (1<<1);
1799 a5e94a9d Alex Bennée
        is_extended = (size < 3) && (opc & 1);
1800 a5e94a9d Alex Bennée
    }
1801 a5e94a9d Alex Bennée
1802 a5e94a9d Alex Bennée
    switch (idx) {
1803 a5e94a9d Alex Bennée
    case 0:
1804 a5e94a9d Alex Bennée
        post_index = false;
1805 a5e94a9d Alex Bennée
        writeback = false;
1806 a5e94a9d Alex Bennée
        break;
1807 a5e94a9d Alex Bennée
    case 1:
1808 a5e94a9d Alex Bennée
        post_index = true;
1809 a5e94a9d Alex Bennée
        writeback = true;
1810 a5e94a9d Alex Bennée
        break;
1811 a5e94a9d Alex Bennée
    case 3:
1812 a5e94a9d Alex Bennée
        post_index = false;
1813 a5e94a9d Alex Bennée
        writeback = true;
1814 a5e94a9d Alex Bennée
        break;
1815 a5e94a9d Alex Bennée
    case 2:
1816 a5e94a9d Alex Bennée
        g_assert(false);
1817 a5e94a9d Alex Bennée
        break;
1818 a5e94a9d Alex Bennée
    }
1819 a5e94a9d Alex Bennée
1820 a5e94a9d Alex Bennée
    if (rn == 31) {
1821 a5e94a9d Alex Bennée
        gen_check_sp_alignment(s);
1822 a5e94a9d Alex Bennée
    }
1823 a5e94a9d Alex Bennée
    tcg_addr = read_cpu_reg_sp(s, rn, 1);
1824 a5e94a9d Alex Bennée
1825 a5e94a9d Alex Bennée
    if (!post_index) {
1826 a5e94a9d Alex Bennée
        tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
1827 a5e94a9d Alex Bennée
    }
1828 a5e94a9d Alex Bennée
1829 a5e94a9d Alex Bennée
    if (is_vector) {
1830 a5e94a9d Alex Bennée
        if (is_store) {
1831 a5e94a9d Alex Bennée
            do_fp_st(s, rt, tcg_addr, size);
1832 a5e94a9d Alex Bennée
        } else {
1833 a5e94a9d Alex Bennée
            do_fp_ld(s, rt, tcg_addr, size);
1834 a5e94a9d Alex Bennée
        }
1835 a5e94a9d Alex Bennée
    } else {
1836 a5e94a9d Alex Bennée
        TCGv_i64 tcg_rt = cpu_reg(s, rt);
1837 a5e94a9d Alex Bennée
        if (is_store) {
1838 a5e94a9d Alex Bennée
            do_gpr_st(s, tcg_rt, tcg_addr, size);
1839 a5e94a9d Alex Bennée
        } else {
1840 a5e94a9d Alex Bennée
            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
1841 a5e94a9d Alex Bennée
        }
1842 a5e94a9d Alex Bennée
    }
1843 a5e94a9d Alex Bennée
1844 a5e94a9d Alex Bennée
    if (writeback) {
1845 a5e94a9d Alex Bennée
        TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
1846 a5e94a9d Alex Bennée
        if (post_index) {
1847 a5e94a9d Alex Bennée
            tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
1848 a5e94a9d Alex Bennée
        }
1849 a5e94a9d Alex Bennée
        tcg_gen_mov_i64(tcg_rn, tcg_addr);
1850 a5e94a9d Alex Bennée
    }
1851 a5e94a9d Alex Bennée
}
1852 a5e94a9d Alex Bennée
1853 a5e94a9d Alex Bennée
/*
1854 229b7a05 Alex Bennée
 * C3.3.10 Load/store (register offset)
1855 229b7a05 Alex Bennée
 *
1856 229b7a05 Alex Bennée
 * 31 30 29   27  26 25 24 23 22 21  20  16 15 13 12 11 10 9  5 4  0
1857 229b7a05 Alex Bennée
 * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
1858 229b7a05 Alex Bennée
 * |size| 1 1 1 | V | 0 0 | opc | 1 |  Rm  | opt | S| 1 0 | Rn | Rt |
1859 229b7a05 Alex Bennée
 * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
1860 229b7a05 Alex Bennée
 *
1861 229b7a05 Alex Bennée
 * For non-vector:
1862 229b7a05 Alex Bennée
 *   size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
1863 229b7a05 Alex Bennée
 *   opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
1864 229b7a05 Alex Bennée
 * For vector:
1865 229b7a05 Alex Bennée
 *   size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
1866 229b7a05 Alex Bennée
 *   opc<0>: 0 -> store, 1 -> load
1867 229b7a05 Alex Bennée
 * V: 1 -> vector/simd
1868 229b7a05 Alex Bennée
 * opt: extend encoding (see DecodeRegExtend)
1869 229b7a05 Alex Bennée
 * S: if S=1 then scale (essentially index by sizeof(size))
1870 229b7a05 Alex Bennée
 * Rt: register to transfer into/out of
1871 229b7a05 Alex Bennée
 * Rn: address register or SP for base
1872 229b7a05 Alex Bennée
 * Rm: offset register or ZR for offset
1873 229b7a05 Alex Bennée
 */
1874 229b7a05 Alex Bennée
static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn)
1875 229b7a05 Alex Bennée
{
1876 229b7a05 Alex Bennée
    int rt = extract32(insn, 0, 5);
1877 229b7a05 Alex Bennée
    int rn = extract32(insn, 5, 5);
1878 229b7a05 Alex Bennée
    int shift = extract32(insn, 12, 1);
1879 229b7a05 Alex Bennée
    int rm = extract32(insn, 16, 5);
1880 229b7a05 Alex Bennée
    int opc = extract32(insn, 22, 2);
1881 229b7a05 Alex Bennée
    int opt = extract32(insn, 13, 3);
1882 229b7a05 Alex Bennée
    int size = extract32(insn, 30, 2);
1883 229b7a05 Alex Bennée
    bool is_signed = false;
1884 229b7a05 Alex Bennée
    bool is_store = false;
1885 229b7a05 Alex Bennée
    bool is_extended = false;
1886 229b7a05 Alex Bennée
    bool is_vector = extract32(insn, 26, 1);
1887 229b7a05 Alex Bennée
1888 229b7a05 Alex Bennée
    TCGv_i64 tcg_rm;
1889 229b7a05 Alex Bennée
    TCGv_i64 tcg_addr;
1890 229b7a05 Alex Bennée
1891 229b7a05 Alex Bennée
    if (extract32(opt, 1, 1) == 0) {
1892 229b7a05 Alex Bennée
        unallocated_encoding(s);
1893 229b7a05 Alex Bennée
        return;
1894 229b7a05 Alex Bennée
    }
1895 229b7a05 Alex Bennée
1896 229b7a05 Alex Bennée
    if (is_vector) {
1897 229b7a05 Alex Bennée
        size |= (opc & 2) << 1;
1898 229b7a05 Alex Bennée
        if (size > 4) {
1899 229b7a05 Alex Bennée
            unallocated_encoding(s);
1900 229b7a05 Alex Bennée
            return;
1901 229b7a05 Alex Bennée
        }
1902 229b7a05 Alex Bennée
        is_store = !extract32(opc, 0, 1);
1903 229b7a05 Alex Bennée
    } else {
1904 229b7a05 Alex Bennée
        if (size == 3 && opc == 2) {
1905 229b7a05 Alex Bennée
            /* PRFM - prefetch */
1906 229b7a05 Alex Bennée
            return;
1907 229b7a05 Alex Bennée
        }
1908 229b7a05 Alex Bennée
        if (opc == 3 && size > 1) {
1909 229b7a05 Alex Bennée
            unallocated_encoding(s);
1910 229b7a05 Alex Bennée
            return;
1911 229b7a05 Alex Bennée
        }
1912 229b7a05 Alex Bennée
        is_store = (opc == 0);
1913 229b7a05 Alex Bennée
        is_signed = extract32(opc, 1, 1);
1914 229b7a05 Alex Bennée
        is_extended = (size < 3) && extract32(opc, 0, 1);
1915 229b7a05 Alex Bennée
    }
1916 229b7a05 Alex Bennée
1917 229b7a05 Alex Bennée
    if (rn == 31) {
1918 229b7a05 Alex Bennée
        gen_check_sp_alignment(s);
1919 229b7a05 Alex Bennée
    }
1920 229b7a05 Alex Bennée
    tcg_addr = read_cpu_reg_sp(s, rn, 1);
1921 229b7a05 Alex Bennée
1922 229b7a05 Alex Bennée
    tcg_rm = read_cpu_reg(s, rm, 1);
1923 229b7a05 Alex Bennée
    ext_and_shift_reg(tcg_rm, tcg_rm, opt, shift ? size : 0);
1924 229b7a05 Alex Bennée
1925 229b7a05 Alex Bennée
    tcg_gen_add_i64(tcg_addr, tcg_addr, tcg_rm);
1926 229b7a05 Alex Bennée
1927 229b7a05 Alex Bennée
    if (is_vector) {
1928 229b7a05 Alex Bennée
        if (is_store) {
1929 229b7a05 Alex Bennée
            do_fp_st(s, rt, tcg_addr, size);
1930 229b7a05 Alex Bennée
        } else {
1931 229b7a05 Alex Bennée
            do_fp_ld(s, rt, tcg_addr, size);
1932 229b7a05 Alex Bennée
        }
1933 229b7a05 Alex Bennée
    } else {
1934 229b7a05 Alex Bennée
        TCGv_i64 tcg_rt = cpu_reg(s, rt);
1935 229b7a05 Alex Bennée
        if (is_store) {
1936 229b7a05 Alex Bennée
            do_gpr_st(s, tcg_rt, tcg_addr, size);
1937 229b7a05 Alex Bennée
        } else {
1938 229b7a05 Alex Bennée
            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
1939 229b7a05 Alex Bennée
        }
1940 229b7a05 Alex Bennée
    }
1941 229b7a05 Alex Bennée
}
1942 229b7a05 Alex Bennée
1943 229b7a05 Alex Bennée
/*
1944 d5612f10 Alex Bennée
 * C3.3.13 Load/store (unsigned immediate)
1945 d5612f10 Alex Bennée
 *
1946 d5612f10 Alex Bennée
 * 31 30 29   27  26 25 24 23 22 21        10 9     5
1947 d5612f10 Alex Bennée
 * +----+-------+---+-----+-----+------------+-------+------+
1948 d5612f10 Alex Bennée
 * |size| 1 1 1 | V | 0 1 | opc |   imm12    |  Rn   |  Rt  |
1949 d5612f10 Alex Bennée
 * +----+-------+---+-----+-----+------------+-------+------+
1950 d5612f10 Alex Bennée
 *
1951 d5612f10 Alex Bennée
 * For non-vector:
1952 d5612f10 Alex Bennée
 *   size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
1953 d5612f10 Alex Bennée
 *   opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
1954 d5612f10 Alex Bennée
 * For vector:
1955 d5612f10 Alex Bennée
 *   size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
1956 d5612f10 Alex Bennée
 *   opc<0>: 0 -> store, 1 -> load
1957 d5612f10 Alex Bennée
 * Rn: base address register (inc SP)
1958 d5612f10 Alex Bennée
 * Rt: target register
1959 d5612f10 Alex Bennée
 */
1960 d5612f10 Alex Bennée
static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn)
1961 d5612f10 Alex Bennée
{
1962 d5612f10 Alex Bennée
    int rt = extract32(insn, 0, 5);
1963 d5612f10 Alex Bennée
    int rn = extract32(insn, 5, 5);
1964 d5612f10 Alex Bennée
    unsigned int imm12 = extract32(insn, 10, 12);
1965 d5612f10 Alex Bennée
    bool is_vector = extract32(insn, 26, 1);
1966 d5612f10 Alex Bennée
    int size = extract32(insn, 30, 2);
1967 d5612f10 Alex Bennée
    int opc = extract32(insn, 22, 2);
1968 d5612f10 Alex Bennée
    unsigned int offset;
1969 d5612f10 Alex Bennée
1970 d5612f10 Alex Bennée
    TCGv_i64 tcg_addr;
1971 d5612f10 Alex Bennée
1972 d5612f10 Alex Bennée
    bool is_store;
1973 d5612f10 Alex Bennée
    bool is_signed = false;
1974 d5612f10 Alex Bennée
    bool is_extended = false;
1975 d5612f10 Alex Bennée
1976 d5612f10 Alex Bennée
    if (is_vector) {
1977 d5612f10 Alex Bennée
        size |= (opc & 2) << 1;
1978 d5612f10 Alex Bennée
        if (size > 4) {
1979 d5612f10 Alex Bennée
            unallocated_encoding(s);
1980 d5612f10 Alex Bennée
            return;
1981 d5612f10 Alex Bennée
        }
1982 d5612f10 Alex Bennée
        is_store = !extract32(opc, 0, 1);
1983 d5612f10 Alex Bennée
    } else {
1984 d5612f10 Alex Bennée
        if (size == 3 && opc == 2) {
1985 d5612f10 Alex Bennée
            /* PRFM - prefetch */
1986 d5612f10 Alex Bennée
            return;
1987 d5612f10 Alex Bennée
        }
1988 d5612f10 Alex Bennée
        if (opc == 3 && size > 1) {
1989 d5612f10 Alex Bennée
            unallocated_encoding(s);
1990 d5612f10 Alex Bennée
            return;
1991 d5612f10 Alex Bennée
        }
1992 d5612f10 Alex Bennée
        is_store = (opc == 0);
1993 d5612f10 Alex Bennée
        is_signed = extract32(opc, 1, 1);
1994 d5612f10 Alex Bennée
        is_extended = (size < 3) && extract32(opc, 0, 1);
1995 d5612f10 Alex Bennée
    }
1996 d5612f10 Alex Bennée
1997 d5612f10 Alex Bennée
    if (rn == 31) {
1998 d5612f10 Alex Bennée
        gen_check_sp_alignment(s);
1999 d5612f10 Alex Bennée
    }
2000 d5612f10 Alex Bennée
    tcg_addr = read_cpu_reg_sp(s, rn, 1);
2001 d5612f10 Alex Bennée
    offset = imm12 << size;
2002 d5612f10 Alex Bennée
    tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
2003 d5612f10 Alex Bennée
2004 d5612f10 Alex Bennée
    if (is_vector) {
2005 d5612f10 Alex Bennée
        if (is_store) {
2006 d5612f10 Alex Bennée
            do_fp_st(s, rt, tcg_addr, size);
2007 d5612f10 Alex Bennée
        } else {
2008 d5612f10 Alex Bennée
            do_fp_ld(s, rt, tcg_addr, size);
2009 d5612f10 Alex Bennée
        }
2010 d5612f10 Alex Bennée
    } else {
2011 d5612f10 Alex Bennée
        TCGv_i64 tcg_rt = cpu_reg(s, rt);
2012 d5612f10 Alex Bennée
        if (is_store) {
2013 d5612f10 Alex Bennée
            do_gpr_st(s, tcg_rt, tcg_addr, size);
2014 d5612f10 Alex Bennée
        } else {
2015 d5612f10 Alex Bennée
            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
2016 d5612f10 Alex Bennée
        }
2017 d5612f10 Alex Bennée
    }
2018 d5612f10 Alex Bennée
}
2019 d5612f10 Alex Bennée
2020 a5e94a9d Alex Bennée
/* Load/store register (immediate forms) */
2021 a5e94a9d Alex Bennée
static void disas_ldst_reg_imm(DisasContext *s, uint32_t insn)
2022 a5e94a9d Alex Bennée
{
2023 a5e94a9d Alex Bennée
    switch (extract32(insn, 10, 2)) {
2024 a5e94a9d Alex Bennée
    case 0: case 1: case 3:
2025 a5e94a9d Alex Bennée
        /* Load/store register (unscaled immediate) */
2026 a5e94a9d Alex Bennée
        /* Load/store immediate pre/post-indexed */
2027 a5e94a9d Alex Bennée
        disas_ldst_reg_imm9(s, insn);
2028 a5e94a9d Alex Bennée
        break;
2029 a5e94a9d Alex Bennée
    case 2:
2030 a5e94a9d Alex Bennée
        /* Load/store register unprivileged */
2031 a5e94a9d Alex Bennée
        unsupported_encoding(s, insn);
2032 a5e94a9d Alex Bennée
        break;
2033 a5e94a9d Alex Bennée
    default:
2034 a5e94a9d Alex Bennée
        unallocated_encoding(s);
2035 a5e94a9d Alex Bennée
        break;
2036 a5e94a9d Alex Bennée
    }
2037 a5e94a9d Alex Bennée
}
2038 a5e94a9d Alex Bennée
2039 ad7ee8a2 Claudio Fontana
/* Load/store register (all forms) */
2040 ad7ee8a2 Claudio Fontana
static void disas_ldst_reg(DisasContext *s, uint32_t insn)
2041 ad7ee8a2 Claudio Fontana
{
2042 d5612f10 Alex Bennée
    switch (extract32(insn, 24, 2)) {
2043 d5612f10 Alex Bennée
    case 0:
2044 229b7a05 Alex Bennée
        if (extract32(insn, 21, 1) == 1 && extract32(insn, 10, 2) == 2) {
2045 229b7a05 Alex Bennée
            disas_ldst_reg_roffset(s, insn);
2046 229b7a05 Alex Bennée
        } else {
2047 a5e94a9d Alex Bennée
            disas_ldst_reg_imm(s, insn);
2048 229b7a05 Alex Bennée
        }
2049 d5612f10 Alex Bennée
        break;
2050 d5612f10 Alex Bennée
    case 1:
2051 d5612f10 Alex Bennée
        disas_ldst_reg_unsigned_imm(s, insn);
2052 d5612f10 Alex Bennée
        break;
2053 d5612f10 Alex Bennée
    default:
2054 d5612f10 Alex Bennée
        unallocated_encoding(s);
2055 d5612f10 Alex Bennée
        break;
2056 d5612f10 Alex Bennée
    }
2057 ad7ee8a2 Claudio Fontana
}
2058 ad7ee8a2 Claudio Fontana
2059 72430bf5 Alex Bennée
/* C3.3.1 AdvSIMD load/store multiple structures
2060 72430bf5 Alex Bennée
 *
2061 72430bf5 Alex Bennée
 *  31  30  29           23 22  21         16 15    12 11  10 9    5 4    0
2062 72430bf5 Alex Bennée
 * +---+---+---------------+---+-------------+--------+------+------+------+
2063 72430bf5 Alex Bennée
 * | 0 | Q | 0 0 1 1 0 0 0 | L | 0 0 0 0 0 0 | opcode | size |  Rn  |  Rt  |
2064 72430bf5 Alex Bennée
 * +---+---+---------------+---+-------------+--------+------+------+------+
2065 72430bf5 Alex Bennée
 *
2066 72430bf5 Alex Bennée
 * C3.3.2 AdvSIMD load/store multiple structures (post-indexed)
2067 72430bf5 Alex Bennée
 *
2068 72430bf5 Alex Bennée
 *  31  30  29           23 22  21  20     16 15    12 11  10 9    5 4    0
2069 72430bf5 Alex Bennée
 * +---+---+---------------+---+---+---------+--------+------+------+------+
2070 72430bf5 Alex Bennée
 * | 0 | Q | 0 0 1 1 0 0 1 | L | 0 |   Rm    | opcode | size |  Rn  |  Rt  |
2071 72430bf5 Alex Bennée
 * +---+---+---------------+---+---+---------+--------+------+------+------+
2072 72430bf5 Alex Bennée
 *
2073 72430bf5 Alex Bennée
 * Rt: first (or only) SIMD&FP register to be transferred
2074 72430bf5 Alex Bennée
 * Rn: base address or SP
2075 72430bf5 Alex Bennée
 * Rm (post-index only): post-index register (when !31) or size dependent #imm
2076 72430bf5 Alex Bennée
 */
2077 ad7ee8a2 Claudio Fontana
static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
2078 ad7ee8a2 Claudio Fontana
{
2079 72430bf5 Alex Bennée
    int rt = extract32(insn, 0, 5);
2080 72430bf5 Alex Bennée
    int rn = extract32(insn, 5, 5);
2081 72430bf5 Alex Bennée
    int size = extract32(insn, 10, 2);
2082 72430bf5 Alex Bennée
    int opcode = extract32(insn, 12, 4);
2083 72430bf5 Alex Bennée
    bool is_store = !extract32(insn, 22, 1);
2084 72430bf5 Alex Bennée
    bool is_postidx = extract32(insn, 23, 1);
2085 72430bf5 Alex Bennée
    bool is_q = extract32(insn, 30, 1);
2086 72430bf5 Alex Bennée
    TCGv_i64 tcg_addr, tcg_rn;
2087 72430bf5 Alex Bennée
2088 72430bf5 Alex Bennée
    int ebytes = 1 << size;
2089 72430bf5 Alex Bennée
    int elements = (is_q ? 128 : 64) / (8 << size);
2090 72430bf5 Alex Bennée
    int rpt;    /* num iterations */
2091 72430bf5 Alex Bennée
    int selem;  /* structure elements */
2092 72430bf5 Alex Bennée
    int r;
2093 72430bf5 Alex Bennée
2094 72430bf5 Alex Bennée
    if (extract32(insn, 31, 1) || extract32(insn, 21, 1)) {
2095 72430bf5 Alex Bennée
        unallocated_encoding(s);
2096 72430bf5 Alex Bennée
        return;
2097 72430bf5 Alex Bennée
    }
2098 72430bf5 Alex Bennée
2099 72430bf5 Alex Bennée
    /* From the shared decode logic */
2100 72430bf5 Alex Bennée
    switch (opcode) {
2101 72430bf5 Alex Bennée
    case 0x0:
2102 72430bf5 Alex Bennée
        rpt = 1;
2103 72430bf5 Alex Bennée
        selem = 4;
2104 72430bf5 Alex Bennée
        break;
2105 72430bf5 Alex Bennée
    case 0x2:
2106 72430bf5 Alex Bennée
        rpt = 4;
2107 72430bf5 Alex Bennée
        selem = 1;
2108 72430bf5 Alex Bennée
        break;
2109 72430bf5 Alex Bennée
    case 0x4:
2110 72430bf5 Alex Bennée
        rpt = 1;
2111 72430bf5 Alex Bennée
        selem = 3;
2112 72430bf5 Alex Bennée
        break;
2113 72430bf5 Alex Bennée
    case 0x6:
2114 72430bf5 Alex Bennée
        rpt = 3;
2115 72430bf5 Alex Bennée
        selem = 1;
2116 72430bf5 Alex Bennée
        break;
2117 72430bf5 Alex Bennée
    case 0x7:
2118 72430bf5 Alex Bennée
        rpt = 1;
2119 72430bf5 Alex Bennée
        selem = 1;
2120 72430bf5 Alex Bennée
        break;
2121 72430bf5 Alex Bennée
    case 0x8:
2122 72430bf5 Alex Bennée
        rpt = 1;
2123 72430bf5 Alex Bennée
        selem = 2;
2124 72430bf5 Alex Bennée
        break;
2125 72430bf5 Alex Bennée
    case 0xa:
2126 72430bf5 Alex Bennée
        rpt = 2;
2127 72430bf5 Alex Bennée
        selem = 1;
2128 72430bf5 Alex Bennée
        break;
2129 72430bf5 Alex Bennée
    default:
2130 72430bf5 Alex Bennée
        unallocated_encoding(s);
2131 72430bf5 Alex Bennée
        return;
2132 72430bf5 Alex Bennée
    }
2133 72430bf5 Alex Bennée
2134 72430bf5 Alex Bennée
    if (size == 3 && !is_q && selem != 1) {
2135 72430bf5 Alex Bennée
        /* reserved */
2136 72430bf5 Alex Bennée
        unallocated_encoding(s);
2137 72430bf5 Alex Bennée
        return;
2138 72430bf5 Alex Bennée
    }
2139 72430bf5 Alex Bennée
2140 72430bf5 Alex Bennée
    if (rn == 31) {
2141 72430bf5 Alex Bennée
        gen_check_sp_alignment(s);
2142 72430bf5 Alex Bennée
    }
2143 72430bf5 Alex Bennée
2144 72430bf5 Alex Bennée
    tcg_rn = cpu_reg_sp(s, rn);
2145 72430bf5 Alex Bennée
    tcg_addr = tcg_temp_new_i64();
2146 72430bf5 Alex Bennée
    tcg_gen_mov_i64(tcg_addr, tcg_rn);
2147 72430bf5 Alex Bennée
2148 72430bf5 Alex Bennée
    for (r = 0; r < rpt; r++) {
2149 72430bf5 Alex Bennée
        int e;
2150 72430bf5 Alex Bennée
        for (e = 0; e < elements; e++) {
2151 72430bf5 Alex Bennée
            int tt = (rt + r) % 32;
2152 72430bf5 Alex Bennée
            int xs;
2153 72430bf5 Alex Bennée
            for (xs = 0; xs < selem; xs++) {
2154 72430bf5 Alex Bennée
                if (is_store) {
2155 72430bf5 Alex Bennée
                    do_vec_st(s, tt, e, tcg_addr, size);
2156 72430bf5 Alex Bennée
                } else {
2157 72430bf5 Alex Bennée
                    do_vec_ld(s, tt, e, tcg_addr, size);
2158 72430bf5 Alex Bennée
2159 72430bf5 Alex Bennée
                    /* For non-quad operations, setting a slice of the low
2160 72430bf5 Alex Bennée
                     * 64 bits of the register clears the high 64 bits (in
2161 72430bf5 Alex Bennée
                     * the ARM ARM pseudocode this is implicit in the fact
2162 72430bf5 Alex Bennée
                     * that 'rval' is a 64 bit wide variable). We optimize
2163 72430bf5 Alex Bennée
                     * by noticing that we only need to do this the first
2164 72430bf5 Alex Bennée
                     * time we touch a register.
2165 72430bf5 Alex Bennée
                     */
2166 72430bf5 Alex Bennée
                    if (!is_q && e == 0 && (r == 0 || xs == selem - 1)) {
2167 72430bf5 Alex Bennée
                        clear_vec_high(s, tt);
2168 72430bf5 Alex Bennée
                    }
2169 72430bf5 Alex Bennée
                }
2170 72430bf5 Alex Bennée
                tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes);
2171 72430bf5 Alex Bennée
                tt = (tt + 1) % 32;
2172 72430bf5 Alex Bennée
            }
2173 72430bf5 Alex Bennée
        }
2174 72430bf5 Alex Bennée
    }
2175 72430bf5 Alex Bennée
2176 72430bf5 Alex Bennée
    if (is_postidx) {
2177 72430bf5 Alex Bennée
        int rm = extract32(insn, 16, 5);
2178 72430bf5 Alex Bennée
        if (rm == 31) {
2179 72430bf5 Alex Bennée
            tcg_gen_mov_i64(tcg_rn, tcg_addr);
2180 72430bf5 Alex Bennée
        } else {
2181 72430bf5 Alex Bennée
            tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
2182 72430bf5 Alex Bennée
        }
2183 72430bf5 Alex Bennée
    }
2184 72430bf5 Alex Bennée
    tcg_temp_free_i64(tcg_addr);
2185 ad7ee8a2 Claudio Fontana
}
2186 ad7ee8a2 Claudio Fontana
2187 df54e47d Peter Maydell
/* C3.3.3 AdvSIMD load/store single structure
2188 df54e47d Peter Maydell
 *
2189 df54e47d Peter Maydell
 *  31  30  29           23 22 21 20       16 15 13 12  11  10 9    5 4    0
2190 df54e47d Peter Maydell
 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
2191 df54e47d Peter Maydell
 * | 0 | Q | 0 0 1 1 0 1 0 | L R | 0 0 0 0 0 | opc | S | size |  Rn  |  Rt  |
2192 df54e47d Peter Maydell
 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
2193 df54e47d Peter Maydell
 *
2194 df54e47d Peter Maydell
 * C3.3.4 AdvSIMD load/store single structure (post-indexed)
2195 df54e47d Peter Maydell
 *
2196 df54e47d Peter Maydell
 *  31  30  29           23 22 21 20       16 15 13 12  11  10 9    5 4    0
2197 df54e47d Peter Maydell
 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
2198 df54e47d Peter Maydell
 * | 0 | Q | 0 0 1 1 0 1 1 | L R |     Rm    | opc | S | size |  Rn  |  Rt  |
2199 df54e47d Peter Maydell
 * +---+---+---------------+-----+-----------+-----+---+------+------+------+
2200 df54e47d Peter Maydell
 *
2201 df54e47d Peter Maydell
 * Rt: first (or only) SIMD&FP register to be transferred
2202 df54e47d Peter Maydell
 * Rn: base address or SP
2203 df54e47d Peter Maydell
 * Rm (post-index only): post-index register (when !31) or size dependent #imm
2204 df54e47d Peter Maydell
 * index = encoded in Q:S:size dependent on size
2205 df54e47d Peter Maydell
 *
2206 df54e47d Peter Maydell
 * lane_size = encoded in R, opc
2207 df54e47d Peter Maydell
 * transfer width = encoded in opc, S, size
2208 df54e47d Peter Maydell
 */
2209 ad7ee8a2 Claudio Fontana
static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
2210 ad7ee8a2 Claudio Fontana
{
2211 df54e47d Peter Maydell
    int rt = extract32(insn, 0, 5);
2212 df54e47d Peter Maydell
    int rn = extract32(insn, 5, 5);
2213 df54e47d Peter Maydell
    int size = extract32(insn, 10, 2);
2214 df54e47d Peter Maydell
    int S = extract32(insn, 12, 1);
2215 df54e47d Peter Maydell
    int opc = extract32(insn, 13, 3);
2216 df54e47d Peter Maydell
    int R = extract32(insn, 21, 1);
2217 df54e47d Peter Maydell
    int is_load = extract32(insn, 22, 1);
2218 df54e47d Peter Maydell
    int is_postidx = extract32(insn, 23, 1);
2219 df54e47d Peter Maydell
    int is_q = extract32(insn, 30, 1);
2220 df54e47d Peter Maydell
2221 df54e47d Peter Maydell
    int scale = extract32(opc, 1, 2);
2222 df54e47d Peter Maydell
    int selem = (extract32(opc, 0, 1) << 1 | R) + 1;
2223 df54e47d Peter Maydell
    bool replicate = false;
2224 df54e47d Peter Maydell
    int index = is_q << 3 | S << 2 | size;
2225 df54e47d Peter Maydell
    int ebytes, xs;
2226 df54e47d Peter Maydell
    TCGv_i64 tcg_addr, tcg_rn;
2227 df54e47d Peter Maydell
2228 df54e47d Peter Maydell
    switch (scale) {
2229 df54e47d Peter Maydell
    case 3:
2230 df54e47d Peter Maydell
        if (!is_load || S) {
2231 df54e47d Peter Maydell
            unallocated_encoding(s);
2232 df54e47d Peter Maydell
            return;
2233 df54e47d Peter Maydell
        }
2234 df54e47d Peter Maydell
        scale = size;
2235 df54e47d Peter Maydell
        replicate = true;
2236 df54e47d Peter Maydell
        break;
2237 df54e47d Peter Maydell
    case 0:
2238 df54e47d Peter Maydell
        break;
2239 df54e47d Peter Maydell
    case 1:
2240 df54e47d Peter Maydell
        if (extract32(size, 0, 1)) {
2241 df54e47d Peter Maydell
            unallocated_encoding(s);
2242 df54e47d Peter Maydell
            return;
2243 df54e47d Peter Maydell
        }
2244 df54e47d Peter Maydell
        index >>= 1;
2245 df54e47d Peter Maydell
        break;
2246 df54e47d Peter Maydell
    case 2:
2247 df54e47d Peter Maydell
        if (extract32(size, 1, 1)) {
2248 df54e47d Peter Maydell
            unallocated_encoding(s);
2249 df54e47d Peter Maydell
            return;
2250 df54e47d Peter Maydell
        }
2251 df54e47d Peter Maydell
        if (!extract32(size, 0, 1)) {
2252 df54e47d Peter Maydell
            index >>= 2;
2253 df54e47d Peter Maydell
        } else {
2254 df54e47d Peter Maydell
            if (S) {
2255 df54e47d Peter Maydell
                unallocated_encoding(s);
2256 df54e47d Peter Maydell
                return;
2257 df54e47d Peter Maydell
            }
2258 df54e47d Peter Maydell
            index >>= 3;
2259 df54e47d Peter Maydell
            scale = 3;
2260 df54e47d Peter Maydell
        }
2261 df54e47d Peter Maydell
        break;
2262 df54e47d Peter Maydell
    default:
2263 df54e47d Peter Maydell
        g_assert_not_reached();
2264 df54e47d Peter Maydell
    }
2265 df54e47d Peter Maydell
2266 df54e47d Peter Maydell
    ebytes = 1 << scale;
2267 df54e47d Peter Maydell
2268 df54e47d Peter Maydell
    if (rn == 31) {
2269 df54e47d Peter Maydell
        gen_check_sp_alignment(s);
2270 df54e47d Peter Maydell
    }
2271 df54e47d Peter Maydell
2272 df54e47d Peter Maydell
    tcg_rn = cpu_reg_sp(s, rn);
2273 df54e47d Peter Maydell
    tcg_addr = tcg_temp_new_i64();
2274 df54e47d Peter Maydell
    tcg_gen_mov_i64(tcg_addr, tcg_rn);
2275 df54e47d Peter Maydell
2276 df54e47d Peter Maydell
    for (xs = 0; xs < selem; xs++) {
2277 df54e47d Peter Maydell
        if (replicate) {
2278 df54e47d Peter Maydell
            /* Load and replicate to all elements */
2279 df54e47d Peter Maydell
            uint64_t mulconst;
2280 df54e47d Peter Maydell
            TCGv_i64 tcg_tmp = tcg_temp_new_i64();
2281 df54e47d Peter Maydell
2282 df54e47d Peter Maydell
            tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr,
2283 df54e47d Peter Maydell
                                get_mem_index(s), MO_TE + scale);
2284 df54e47d Peter Maydell
            switch (scale) {
2285 df54e47d Peter Maydell
            case 0:
2286 df54e47d Peter Maydell
                mulconst = 0x0101010101010101ULL;
2287 df54e47d Peter Maydell
                break;
2288 df54e47d Peter Maydell
            case 1:
2289 df54e47d Peter Maydell
                mulconst = 0x0001000100010001ULL;
2290 df54e47d Peter Maydell
                break;
2291 df54e47d Peter Maydell
            case 2:
2292 df54e47d Peter Maydell
                mulconst = 0x0000000100000001ULL;
2293 df54e47d Peter Maydell
                break;
2294 df54e47d Peter Maydell
            case 3:
2295 df54e47d Peter Maydell
                mulconst = 0;
2296 df54e47d Peter Maydell
                break;
2297 df54e47d Peter Maydell
            default:
2298 df54e47d Peter Maydell
                g_assert_not_reached();
2299 df54e47d Peter Maydell
            }
2300 df54e47d Peter Maydell
            if (mulconst) {
2301 df54e47d Peter Maydell
                tcg_gen_muli_i64(tcg_tmp, tcg_tmp, mulconst);
2302 df54e47d Peter Maydell
            }
2303 df54e47d Peter Maydell
            write_vec_element(s, tcg_tmp, rt, 0, MO_64);
2304 df54e47d Peter Maydell
            if (is_q) {
2305 df54e47d Peter Maydell
                write_vec_element(s, tcg_tmp, rt, 1, MO_64);
2306 df54e47d Peter Maydell
            } else {
2307 df54e47d Peter Maydell
                clear_vec_high(s, rt);
2308 df54e47d Peter Maydell
            }
2309 df54e47d Peter Maydell
            tcg_temp_free_i64(tcg_tmp);
2310 df54e47d Peter Maydell
        } else {
2311 df54e47d Peter Maydell
            /* Load/store one element per register */
2312 df54e47d Peter Maydell
            if (is_load) {
2313 df54e47d Peter Maydell
                do_vec_ld(s, rt, index, tcg_addr, MO_TE + scale);
2314 df54e47d Peter Maydell
            } else {
2315 df54e47d Peter Maydell
                do_vec_st(s, rt, index, tcg_addr, MO_TE + scale);
2316 df54e47d Peter Maydell
            }
2317 df54e47d Peter Maydell
        }
2318 df54e47d Peter Maydell
        tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes);
2319 df54e47d Peter Maydell
        rt = (rt + 1) % 32;
2320 df54e47d Peter Maydell
    }
2321 df54e47d Peter Maydell
2322 df54e47d Peter Maydell
    if (is_postidx) {
2323 df54e47d Peter Maydell
        int rm = extract32(insn, 16, 5);
2324 df54e47d Peter Maydell
        if (rm == 31) {
2325 df54e47d Peter Maydell
            tcg_gen_mov_i64(tcg_rn, tcg_addr);
2326 df54e47d Peter Maydell
        } else {
2327 df54e47d Peter Maydell
            tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
2328 df54e47d Peter Maydell
        }
2329 df54e47d Peter Maydell
    }
2330 df54e47d Peter Maydell
    tcg_temp_free_i64(tcg_addr);
2331 ad7ee8a2 Claudio Fontana
}
2332 ad7ee8a2 Claudio Fontana
2333 ad7ee8a2 Claudio Fontana
/* C3.3 Loads and stores */
2334 ad7ee8a2 Claudio Fontana
static void disas_ldst(DisasContext *s, uint32_t insn)
2335 ad7ee8a2 Claudio Fontana
{
2336 ad7ee8a2 Claudio Fontana
    switch (extract32(insn, 24, 6)) {
2337 ad7ee8a2 Claudio Fontana
    case 0x08: /* Load/store exclusive */
2338 ad7ee8a2 Claudio Fontana
        disas_ldst_excl(s, insn);
2339 ad7ee8a2 Claudio Fontana
        break;
2340 ad7ee8a2 Claudio Fontana
    case 0x18: case 0x1c: /* Load register (literal) */
2341 ad7ee8a2 Claudio Fontana
        disas_ld_lit(s, insn);
2342 ad7ee8a2 Claudio Fontana
        break;
2343 ad7ee8a2 Claudio Fontana
    case 0x28: case 0x29:
2344 ad7ee8a2 Claudio Fontana
    case 0x2c: case 0x2d: /* Load/store pair (all forms) */
2345 ad7ee8a2 Claudio Fontana
        disas_ldst_pair(s, insn);
2346 ad7ee8a2 Claudio Fontana
        break;
2347 ad7ee8a2 Claudio Fontana
    case 0x38: case 0x39:
2348 ad7ee8a2 Claudio Fontana
    case 0x3c: case 0x3d: /* Load/store register (all forms) */
2349 ad7ee8a2 Claudio Fontana
        disas_ldst_reg(s, insn);
2350 ad7ee8a2 Claudio Fontana
        break;
2351 ad7ee8a2 Claudio Fontana
    case 0x0c: /* AdvSIMD load/store multiple structures */
2352 ad7ee8a2 Claudio Fontana
        disas_ldst_multiple_struct(s, insn);
2353 ad7ee8a2 Claudio Fontana
        break;
2354 ad7ee8a2 Claudio Fontana
    case 0x0d: /* AdvSIMD load/store single structure */
2355 ad7ee8a2 Claudio Fontana
        disas_ldst_single_struct(s, insn);
2356 ad7ee8a2 Claudio Fontana
        break;
2357 ad7ee8a2 Claudio Fontana
    default:
2358 ad7ee8a2 Claudio Fontana
        unallocated_encoding(s);
2359 ad7ee8a2 Claudio Fontana
        break;
2360 ad7ee8a2 Claudio Fontana
    }
2361 ad7ee8a2 Claudio Fontana
}
2362 ad7ee8a2 Claudio Fontana
2363 15bfe8b6 Alexander Graf
/* C3.4.6 PC-rel. addressing
2364 15bfe8b6 Alexander Graf
 *   31  30   29 28       24 23                5 4    0
2365 15bfe8b6 Alexander Graf
 * +----+-------+-----------+-------------------+------+
2366 15bfe8b6 Alexander Graf
 * | op | immlo | 1 0 0 0 0 |       immhi       |  Rd  |
2367 15bfe8b6 Alexander Graf
 * +----+-------+-----------+-------------------+------+
2368 15bfe8b6 Alexander Graf
 */
2369 ad7ee8a2 Claudio Fontana
static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
2370 ad7ee8a2 Claudio Fontana
{
2371 15bfe8b6 Alexander Graf
    unsigned int page, rd;
2372 15bfe8b6 Alexander Graf
    uint64_t base;
2373 15bfe8b6 Alexander Graf
    int64_t offset;
2374 15bfe8b6 Alexander Graf
2375 15bfe8b6 Alexander Graf
    page = extract32(insn, 31, 1);
2376 15bfe8b6 Alexander Graf
    /* SignExtend(immhi:immlo) -> offset */
2377 15bfe8b6 Alexander Graf
    offset = ((int64_t)sextract32(insn, 5, 19) << 2) | extract32(insn, 29, 2);
2378 15bfe8b6 Alexander Graf
    rd = extract32(insn, 0, 5);
2379 15bfe8b6 Alexander Graf
    base = s->pc - 4;
2380 15bfe8b6 Alexander Graf
2381 15bfe8b6 Alexander Graf
    if (page) {
2382 15bfe8b6 Alexander Graf
        /* ADRP (page based) */
2383 15bfe8b6 Alexander Graf
        base &= ~0xfff;
2384 15bfe8b6 Alexander Graf
        offset <<= 12;
2385 15bfe8b6 Alexander Graf
    }
2386 15bfe8b6 Alexander Graf
2387 15bfe8b6 Alexander Graf
    tcg_gen_movi_i64(cpu_reg(s, rd), base + offset);
2388 ad7ee8a2 Claudio Fontana
}
2389 ad7ee8a2 Claudio Fontana
2390 b0ff21b4 Alex Bennée
/*
2391 b0ff21b4 Alex Bennée
 * C3.4.1 Add/subtract (immediate)
2392 b0ff21b4 Alex Bennée
 *
2393 b0ff21b4 Alex Bennée
 *  31 30 29 28       24 23 22 21         10 9   5 4   0
2394 b0ff21b4 Alex Bennée
 * +--+--+--+-----------+-----+-------------+-----+-----+
2395 b0ff21b4 Alex Bennée
 * |sf|op| S| 1 0 0 0 1 |shift|    imm12    |  Rn | Rd  |
2396 b0ff21b4 Alex Bennée
 * +--+--+--+-----------+-----+-------------+-----+-----+
2397 b0ff21b4 Alex Bennée
 *
2398 b0ff21b4 Alex Bennée
 *    sf: 0 -> 32bit, 1 -> 64bit
2399 b0ff21b4 Alex Bennée
 *    op: 0 -> add  , 1 -> sub
2400 b0ff21b4 Alex Bennée
 *     S: 1 -> set flags
2401 b0ff21b4 Alex Bennée
 * shift: 00 -> LSL imm by 0, 01 -> LSL imm by 12
2402 b0ff21b4 Alex Bennée
 */
2403 ad7ee8a2 Claudio Fontana
static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
2404 ad7ee8a2 Claudio Fontana
{
2405 b0ff21b4 Alex Bennée
    int rd = extract32(insn, 0, 5);
2406 b0ff21b4 Alex Bennée
    int rn = extract32(insn, 5, 5);
2407 b0ff21b4 Alex Bennée
    uint64_t imm = extract32(insn, 10, 12);
2408 b0ff21b4 Alex Bennée
    int shift = extract32(insn, 22, 2);
2409 b0ff21b4 Alex Bennée
    bool setflags = extract32(insn, 29, 1);
2410 b0ff21b4 Alex Bennée
    bool sub_op = extract32(insn, 30, 1);
2411 b0ff21b4 Alex Bennée
    bool is_64bit = extract32(insn, 31, 1);
2412 b0ff21b4 Alex Bennée
2413 b0ff21b4 Alex Bennée
    TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
2414 b0ff21b4 Alex Bennée
    TCGv_i64 tcg_rd = setflags ? cpu_reg(s, rd) : cpu_reg_sp(s, rd);
2415 b0ff21b4 Alex Bennée
    TCGv_i64 tcg_result;
2416 b0ff21b4 Alex Bennée
2417 b0ff21b4 Alex Bennée
    switch (shift) {
2418 b0ff21b4 Alex Bennée
    case 0x0:
2419 b0ff21b4 Alex Bennée
        break;
2420 b0ff21b4 Alex Bennée
    case 0x1:
2421 b0ff21b4 Alex Bennée
        imm <<= 12;
2422 b0ff21b4 Alex Bennée
        break;
2423 b0ff21b4 Alex Bennée
    default:
2424 b0ff21b4 Alex Bennée
        unallocated_encoding(s);
2425 b0ff21b4 Alex Bennée
        return;
2426 b0ff21b4 Alex Bennée
    }
2427 b0ff21b4 Alex Bennée
2428 b0ff21b4 Alex Bennée
    tcg_result = tcg_temp_new_i64();
2429 b0ff21b4 Alex Bennée
    if (!setflags) {
2430 b0ff21b4 Alex Bennée
        if (sub_op) {
2431 b0ff21b4 Alex Bennée
            tcg_gen_subi_i64(tcg_result, tcg_rn, imm);
2432 b0ff21b4 Alex Bennée
        } else {
2433 b0ff21b4 Alex Bennée
            tcg_gen_addi_i64(tcg_result, tcg_rn, imm);
2434 b0ff21b4 Alex Bennée
        }
2435 b0ff21b4 Alex Bennée
    } else {
2436 b0ff21b4 Alex Bennée
        TCGv_i64 tcg_imm = tcg_const_i64(imm);
2437 b0ff21b4 Alex Bennée
        if (sub_op) {
2438 b0ff21b4 Alex Bennée
            gen_sub_CC(is_64bit, tcg_result, tcg_rn, tcg_imm);
2439 b0ff21b4 Alex Bennée
        } else {
2440 b0ff21b4 Alex Bennée
            gen_add_CC(is_64bit, tcg_result, tcg_rn, tcg_imm);
2441 b0ff21b4 Alex Bennée
        }
2442 b0ff21b4 Alex Bennée
        tcg_temp_free_i64(tcg_imm);
2443 b0ff21b4 Alex Bennée
    }
2444 b0ff21b4 Alex Bennée
2445 b0ff21b4 Alex Bennée
    if (is_64bit) {
2446 b0ff21b4 Alex Bennée
        tcg_gen_mov_i64(tcg_rd, tcg_result);
2447 b0ff21b4 Alex Bennée
    } else {
2448 b0ff21b4 Alex Bennée
        tcg_gen_ext32u_i64(tcg_rd, tcg_result);
2449 b0ff21b4 Alex Bennée
    }
2450 b0ff21b4 Alex Bennée
2451 b0ff21b4 Alex Bennée
    tcg_temp_free_i64(tcg_result);
2452 ad7ee8a2 Claudio Fontana
}
2453 ad7ee8a2 Claudio Fontana
2454 71b46089 Alexander Graf
/* The input should be a value in the bottom e bits (with higher
2455 71b46089 Alexander Graf
 * bits zero); returns that value replicated into every element
2456 71b46089 Alexander Graf
 * of size e in a 64 bit integer.
2457 71b46089 Alexander Graf
 */
2458 71b46089 Alexander Graf
static uint64_t bitfield_replicate(uint64_t mask, unsigned int e)
2459 71b46089 Alexander Graf
{
2460 71b46089 Alexander Graf
    assert(e != 0);
2461 71b46089 Alexander Graf
    while (e < 64) {
2462 71b46089 Alexander Graf
        mask |= mask << e;
2463 71b46089 Alexander Graf
        e *= 2;
2464 71b46089 Alexander Graf
    }
2465 71b46089 Alexander Graf
    return mask;
2466 71b46089 Alexander Graf
}
2467 71b46089 Alexander Graf
2468 71b46089 Alexander Graf
/* Return a value with the bottom len bits set (where 0 < len <= 64) */
2469 71b46089 Alexander Graf
static inline uint64_t bitmask64(unsigned int length)
2470 71b46089 Alexander Graf
{
2471 71b46089 Alexander Graf
    assert(length > 0 && length <= 64);
2472 71b46089 Alexander Graf
    return ~0ULL >> (64 - length);
2473 71b46089 Alexander Graf
}
2474 71b46089 Alexander Graf
2475 71b46089 Alexander Graf
/* Simplified variant of pseudocode DecodeBitMasks() for the case where we
2476 71b46089 Alexander Graf
 * only require the wmask. Returns false if the imms/immr/immn are a reserved
2477 71b46089 Alexander Graf
 * value (ie should cause a guest UNDEF exception), and true if they are
2478 71b46089 Alexander Graf
 * valid, in which case the decoded bit pattern is written to result.
2479 71b46089 Alexander Graf
 */
2480 71b46089 Alexander Graf
static bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
2481 71b46089 Alexander Graf
                                   unsigned int imms, unsigned int immr)
2482 71b46089 Alexander Graf
{
2483 71b46089 Alexander Graf
    uint64_t mask;
2484 71b46089 Alexander Graf
    unsigned e, levels, s, r;
2485 71b46089 Alexander Graf
    int len;
2486 71b46089 Alexander Graf
2487 71b46089 Alexander Graf
    assert(immn < 2 && imms < 64 && immr < 64);
2488 71b46089 Alexander Graf
2489 71b46089 Alexander Graf
    /* The bit patterns we create here are 64 bit patterns which
2490 71b46089 Alexander Graf
     * are vectors of identical elements of size e = 2, 4, 8, 16, 32 or
2491 71b46089 Alexander Graf
     * 64 bits each. Each element contains the same value: a run
2492 71b46089 Alexander Graf
     * of between 1 and e-1 non-zero bits, rotated within the
2493 71b46089 Alexander Graf
     * element by between 0 and e-1 bits.
2494 71b46089 Alexander Graf
     *
2495 71b46089 Alexander Graf
     * The element size and run length are encoded into immn (1 bit)
2496 71b46089 Alexander Graf
     * and imms (6 bits) as follows:
2497 71b46089 Alexander Graf
     * 64 bit elements: immn = 1, imms = <length of run - 1>
2498 71b46089 Alexander Graf
     * 32 bit elements: immn = 0, imms = 0 : <length of run - 1>
2499 71b46089 Alexander Graf
     * 16 bit elements: immn = 0, imms = 10 : <length of run - 1>
2500 71b46089 Alexander Graf
     *  8 bit elements: immn = 0, imms = 110 : <length of run - 1>
2501 71b46089 Alexander Graf
     *  4 bit elements: immn = 0, imms = 1110 : <length of run - 1>
2502 71b46089 Alexander Graf
     *  2 bit elements: immn = 0, imms = 11110 : <length of run - 1>
2503 71b46089 Alexander Graf
     * Notice that immn = 0, imms = 11111x is the only combination
2504 71b46089 Alexander Graf
     * not covered by one of the above options; this is reserved.
2505 71b46089 Alexander Graf
     * Further, <length of run - 1> all-ones is a reserved pattern.
2506 71b46089 Alexander Graf
     *
2507 71b46089 Alexander Graf
     * In all cases the rotation is by immr % e (and immr is 6 bits).
2508 71b46089 Alexander Graf
     */
2509 71b46089 Alexander Graf
2510 71b46089 Alexander Graf
    /* First determine the element size */
2511 71b46089 Alexander Graf
    len = 31 - clz32((immn << 6) | (~imms & 0x3f));
2512 71b46089 Alexander Graf
    if (len < 1) {
2513 71b46089 Alexander Graf
        /* This is the immn == 0, imms == 0x11111x case */
2514 71b46089 Alexander Graf
        return false;
2515 71b46089 Alexander Graf
    }
2516 71b46089 Alexander Graf
    e = 1 << len;
2517 71b46089 Alexander Graf
2518 71b46089 Alexander Graf
    levels = e - 1;
2519 71b46089 Alexander Graf
    s = imms & levels;
2520 71b46089 Alexander Graf
    r = immr & levels;
2521 71b46089 Alexander Graf
2522 71b46089 Alexander Graf
    if (s == levels) {
2523 71b46089 Alexander Graf
        /* <length of run - 1> mustn't be all-ones. */
2524 71b46089 Alexander Graf
        return false;
2525 71b46089 Alexander Graf
    }
2526 71b46089 Alexander Graf
2527 71b46089 Alexander Graf
    /* Create the value of one element: s+1 set bits rotated
2528 71b46089 Alexander Graf
     * by r within the element (which is e bits wide)...
2529 71b46089 Alexander Graf
     */
2530 71b46089 Alexander Graf
    mask = bitmask64(s + 1);
2531 71b46089 Alexander Graf
    mask = (mask >> r) | (mask << (e - r));
2532 71b46089 Alexander Graf
    /* ...then replicate the element over the whole 64 bit value */
2533 71b46089 Alexander Graf
    mask = bitfield_replicate(mask, e);
2534 71b46089 Alexander Graf
    *result = mask;
2535 71b46089 Alexander Graf
    return true;
2536 71b46089 Alexander Graf
}
2537 71b46089 Alexander Graf
2538 71b46089 Alexander Graf
/* C3.4.4 Logical (immediate)
2539 71b46089 Alexander Graf
 *   31  30 29 28         23 22  21  16 15  10 9    5 4    0
2540 71b46089 Alexander Graf
 * +----+-----+-------------+---+------+------+------+------+
2541 71b46089 Alexander Graf
 * | sf | opc | 1 0 0 1 0 0 | N | immr | imms |  Rn  |  Rd  |
2542 71b46089 Alexander Graf
 * +----+-----+-------------+---+------+------+------+------+
2543 71b46089 Alexander Graf
 */
2544 ad7ee8a2 Claudio Fontana
static void disas_logic_imm(DisasContext *s, uint32_t insn)
2545 ad7ee8a2 Claudio Fontana
{
2546 71b46089 Alexander Graf
    unsigned int sf, opc, is_n, immr, imms, rn, rd;
2547 71b46089 Alexander Graf
    TCGv_i64 tcg_rd, tcg_rn;
2548 71b46089 Alexander Graf
    uint64_t wmask;
2549 71b46089 Alexander Graf
    bool is_and = false;
2550 71b46089 Alexander Graf
2551 71b46089 Alexander Graf
    sf = extract32(insn, 31, 1);
2552 71b46089 Alexander Graf
    opc = extract32(insn, 29, 2);
2553 71b46089 Alexander Graf
    is_n = extract32(insn, 22, 1);
2554 71b46089 Alexander Graf
    immr = extract32(insn, 16, 6);
2555 71b46089 Alexander Graf
    imms = extract32(insn, 10, 6);
2556 71b46089 Alexander Graf
    rn = extract32(insn, 5, 5);
2557 71b46089 Alexander Graf
    rd = extract32(insn, 0, 5);
2558 71b46089 Alexander Graf
2559 71b46089 Alexander Graf
    if (!sf && is_n) {
2560 71b46089 Alexander Graf
        unallocated_encoding(s);
2561 71b46089 Alexander Graf
        return;
2562 71b46089 Alexander Graf
    }
2563 71b46089 Alexander Graf
2564 71b46089 Alexander Graf
    if (opc == 0x3) { /* ANDS */
2565 71b46089 Alexander Graf
        tcg_rd = cpu_reg(s, rd);
2566 71b46089 Alexander Graf
    } else {
2567 71b46089 Alexander Graf
        tcg_rd = cpu_reg_sp(s, rd);
2568 71b46089 Alexander Graf
    }
2569 71b46089 Alexander Graf
    tcg_rn = cpu_reg(s, rn);
2570 71b46089 Alexander Graf
2571 71b46089 Alexander Graf
    if (!logic_imm_decode_wmask(&wmask, is_n, imms, immr)) {
2572 71b46089 Alexander Graf
        /* some immediate field values are reserved */
2573 71b46089 Alexander Graf
        unallocated_encoding(s);
2574 71b46089 Alexander Graf
        return;
2575 71b46089 Alexander Graf
    }
2576 71b46089 Alexander Graf
2577 71b46089 Alexander Graf
    if (!sf) {
2578 71b46089 Alexander Graf
        wmask &= 0xffffffff;
2579 71b46089 Alexander Graf
    }
2580 71b46089 Alexander Graf
2581 71b46089 Alexander Graf
    switch (opc) {
2582 71b46089 Alexander Graf
    case 0x3: /* ANDS */
2583 71b46089 Alexander Graf
    case 0x0: /* AND */
2584 71b46089 Alexander Graf
        tcg_gen_andi_i64(tcg_rd, tcg_rn, wmask);
2585 71b46089 Alexander Graf
        is_and = true;
2586 71b46089 Alexander Graf
        break;
2587 71b46089 Alexander Graf
    case 0x1: /* ORR */
2588 71b46089 Alexander Graf
        tcg_gen_ori_i64(tcg_rd, tcg_rn, wmask);
2589 71b46089 Alexander Graf
        break;
2590 71b46089 Alexander Graf
    case 0x2: /* EOR */
2591 71b46089 Alexander Graf
        tcg_gen_xori_i64(tcg_rd, tcg_rn, wmask);
2592 71b46089 Alexander Graf
        break;
2593 71b46089 Alexander Graf
    default:
2594 71b46089 Alexander Graf
        assert(FALSE); /* must handle all above */
2595 71b46089 Alexander Graf
        break;
2596 71b46089 Alexander Graf
    }
2597 71b46089 Alexander Graf
2598 71b46089 Alexander Graf
    if (!sf && !is_and) {
2599 71b46089 Alexander Graf
        /* zero extend final result; we know we can skip this for AND
2600 71b46089 Alexander Graf
         * since the immediate had the high 32 bits clear.
2601 71b46089 Alexander Graf
         */
2602 71b46089 Alexander Graf
        tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
2603 71b46089 Alexander Graf
    }
2604 71b46089 Alexander Graf
2605 71b46089 Alexander Graf
    if (opc == 3) { /* ANDS */
2606 71b46089 Alexander Graf
        gen_logic_CC(sf, tcg_rd);
2607 71b46089 Alexander Graf
    }
2608 ad7ee8a2 Claudio Fontana
}
2609 ad7ee8a2 Claudio Fontana
2610 ed6ec679 Alex Bennée
/*
2611 ed6ec679 Alex Bennée
 * C3.4.5 Move wide (immediate)
2612 ed6ec679 Alex Bennée
 *
2613 ed6ec679 Alex Bennée
 *  31 30 29 28         23 22 21 20             5 4    0
2614 ed6ec679 Alex Bennée
 * +--+-----+-------------+-----+----------------+------+
2615 ed6ec679 Alex Bennée
 * |sf| opc | 1 0 0 1 0 1 |  hw |  imm16         |  Rd  |
2616 ed6ec679 Alex Bennée
 * +--+-----+-------------+-----+----------------+------+
2617 ed6ec679 Alex Bennée
 *
2618 ed6ec679 Alex Bennée
 * sf: 0 -> 32 bit, 1 -> 64 bit
2619 ed6ec679 Alex Bennée
 * opc: 00 -> N, 10 -> Z, 11 -> K
2620 ed6ec679 Alex Bennée
 * hw: shift/16 (0,16, and sf only 32, 48)
2621 ed6ec679 Alex Bennée
 */
2622 ad7ee8a2 Claudio Fontana
static void disas_movw_imm(DisasContext *s, uint32_t insn)
2623 ad7ee8a2 Claudio Fontana
{
2624 ed6ec679 Alex Bennée
    int rd = extract32(insn, 0, 5);
2625 ed6ec679 Alex Bennée
    uint64_t imm = extract32(insn, 5, 16);
2626 ed6ec679 Alex Bennée
    int sf = extract32(insn, 31, 1);
2627 ed6ec679 Alex Bennée
    int opc = extract32(insn, 29, 2);
2628 ed6ec679 Alex Bennée
    int pos = extract32(insn, 21, 2) << 4;
2629 ed6ec679 Alex Bennée
    TCGv_i64 tcg_rd = cpu_reg(s, rd);
2630 ed6ec679 Alex Bennée
    TCGv_i64 tcg_imm;
2631 ed6ec679 Alex Bennée
2632 ed6ec679 Alex Bennée
    if (!sf && (pos >= 32)) {
2633 ed6ec679 Alex Bennée
        unallocated_encoding(s);
2634 ed6ec679 Alex Bennée
        return;
2635 ed6ec679 Alex Bennée
    }
2636 ed6ec679 Alex Bennée
2637 ed6ec679 Alex Bennée
    switch (opc) {
2638 ed6ec679 Alex Bennée
    case 0: /* MOVN */
2639 ed6ec679 Alex Bennée
    case 2: /* MOVZ */
2640 ed6ec679 Alex Bennée
        imm <<= pos;
2641 ed6ec679 Alex Bennée
        if (opc == 0) {
2642 ed6ec679 Alex Bennée
            imm = ~imm;
2643 ed6ec679 Alex Bennée
        }
2644 ed6ec679 Alex Bennée
        if (!sf) {
2645 ed6ec679 Alex Bennée
            imm &= 0xffffffffu;
2646 ed6ec679 Alex Bennée
        }
2647 ed6ec679 Alex Bennée
        tcg_gen_movi_i64(tcg_rd, imm);
2648 ed6ec679 Alex Bennée
        break;
2649 ed6ec679 Alex Bennée
    case 3: /* MOVK */
2650 ed6ec679 Alex Bennée
        tcg_imm = tcg_const_i64(imm);
2651 ed6ec679 Alex Bennée
        tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_imm, pos, 16);
2652 ed6ec679 Alex Bennée
        tcg_temp_free_i64(tcg_imm);
2653 ed6ec679 Alex Bennée
        if (!sf) {
2654 ed6ec679 Alex Bennée
            tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
2655 ed6ec679 Alex Bennée
        }
2656 ed6ec679 Alex Bennée
        break;
2657 ed6ec679 Alex Bennée
    default:
2658 ed6ec679 Alex Bennée
        unallocated_encoding(s);
2659 ed6ec679 Alex Bennée
        break;
2660 ed6ec679 Alex Bennée
    }
2661 ad7ee8a2 Claudio Fontana
}
2662 ad7ee8a2 Claudio Fontana
2663 88077742 Claudio Fontana
/* C3.4.2 Bitfield
2664 88077742 Claudio Fontana
 *   31  30 29 28         23 22  21  16 15  10 9    5 4    0
2665 88077742 Claudio Fontana
 * +----+-----+-------------+---+------+------+------+------+
2666 88077742 Claudio Fontana
 * | sf | opc | 1 0 0 1 1 0 | N | immr | imms |  Rn  |  Rd  |
2667 88077742 Claudio Fontana
 * +----+-----+-------------+---+------+------+------+------+
2668 88077742 Claudio Fontana
 */
2669 ad7ee8a2 Claudio Fontana
static void disas_bitfield(DisasContext *s, uint32_t insn)
2670 ad7ee8a2 Claudio Fontana
{
2671 88077742 Claudio Fontana
    unsigned int sf, n, opc, ri, si, rn, rd, bitsize, pos, len;
2672 88077742 Claudio Fontana
    TCGv_i64 tcg_rd, tcg_tmp;
2673 88077742 Claudio Fontana
2674 88077742 Claudio Fontana
    sf = extract32(insn, 31, 1);
2675 88077742 Claudio Fontana
    opc = extract32(insn, 29, 2);
2676 88077742 Claudio Fontana
    n = extract32(insn, 22, 1);
2677 88077742 Claudio Fontana
    ri = extract32(insn, 16, 6);
2678 88077742 Claudio Fontana
    si = extract32(insn, 10, 6);
2679 88077742 Claudio Fontana
    rn = extract32(insn, 5, 5);
2680 88077742 Claudio Fontana
    rd = extract32(insn, 0, 5);
2681 88077742 Claudio Fontana
    bitsize = sf ? 64 : 32;
2682 88077742 Claudio Fontana
2683 88077742 Claudio Fontana
    if (sf != n || ri >= bitsize || si >= bitsize || opc > 2) {
2684 88077742 Claudio Fontana
        unallocated_encoding(s);
2685 88077742 Claudio Fontana
        return;
2686 88077742 Claudio Fontana
    }
2687 88077742 Claudio Fontana
2688 88077742 Claudio Fontana
    tcg_rd = cpu_reg(s, rd);
2689 88077742 Claudio Fontana
    tcg_tmp = read_cpu_reg(s, rn, sf);
2690 88077742 Claudio Fontana
2691 88077742 Claudio Fontana
    /* OPTME: probably worth recognizing common cases of ext{8,16,32}{u,s} */
2692 88077742 Claudio Fontana
2693 88077742 Claudio Fontana
    if (opc != 1) { /* SBFM or UBFM */
2694 88077742 Claudio Fontana
        tcg_gen_movi_i64(tcg_rd, 0);
2695 88077742 Claudio Fontana
    }
2696 88077742 Claudio Fontana
2697 88077742 Claudio Fontana
    /* do the bit move operation */
2698 88077742 Claudio Fontana
    if (si >= ri) {
2699 88077742 Claudio Fontana
        /* Wd<s-r:0> = Wn<s:r> */
2700 88077742 Claudio Fontana
        tcg_gen_shri_i64(tcg_tmp, tcg_tmp, ri);
2701 88077742 Claudio Fontana
        pos = 0;
2702 88077742 Claudio Fontana
        len = (si - ri) + 1;
2703 88077742 Claudio Fontana
    } else {
2704 88077742 Claudio Fontana
        /* Wd<32+s-r,32-r> = Wn<s:0> */
2705 88077742 Claudio Fontana
        pos = bitsize - ri;
2706 88077742 Claudio Fontana
        len = si + 1;
2707 88077742 Claudio Fontana
    }
2708 88077742 Claudio Fontana
2709 88077742 Claudio Fontana
    tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, pos, len);
2710 88077742 Claudio Fontana
2711 88077742 Claudio Fontana
    if (opc == 0) { /* SBFM - sign extend the destination field */
2712 88077742 Claudio Fontana
        tcg_gen_shli_i64(tcg_rd, tcg_rd, 64 - (pos + len));
2713 88077742 Claudio Fontana
        tcg_gen_sari_i64(tcg_rd, tcg_rd, 64 - (pos + len));
2714 88077742 Claudio Fontana
    }
2715 88077742 Claudio Fontana
2716 88077742 Claudio Fontana
    if (!sf) { /* zero extend final result */
2717 88077742 Claudio Fontana
        tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
2718 88077742 Claudio Fontana
    }
2719 ad7ee8a2 Claudio Fontana
}
2720 ad7ee8a2 Claudio Fontana
2721 e801de93 Alexander Graf
/* C3.4.3 Extract
2722 e801de93 Alexander Graf
 *   31  30  29 28         23 22   21  20  16 15    10 9    5 4    0
2723 e801de93 Alexander Graf
 * +----+------+-------------+---+----+------+--------+------+------+
2724 e801de93 Alexander Graf
 * | sf | op21 | 1 0 0 1 1 1 | N | o0 |  Rm  |  imms  |  Rn  |  Rd  |
2725 e801de93 Alexander Graf
 * +----+------+-------------+---+----+------+--------+------+------+
2726 e801de93 Alexander Graf
 */
2727 ad7ee8a2 Claudio Fontana
static void disas_extract(DisasContext *s, uint32_t insn)
2728 ad7ee8a2 Claudio Fontana
{
2729 e801de93 Alexander Graf
    unsigned int sf, n, rm, imm, rn, rd, bitsize, op21, op0;
2730 e801de93 Alexander Graf
2731 e801de93 Alexander Graf
    sf = extract32(insn, 31, 1);
2732 e801de93 Alexander Graf
    n = extract32(insn, 22, 1);
2733 e801de93 Alexander Graf
    rm = extract32(insn, 16, 5);
2734 e801de93 Alexander Graf
    imm = extract32(insn, 10, 6);
2735 e801de93 Alexander Graf
    rn = extract32(insn, 5, 5);
2736 e801de93 Alexander Graf
    rd = extract32(insn, 0, 5);
2737 e801de93 Alexander Graf
    op21 = extract32(insn, 29, 2);
2738 e801de93 Alexander Graf
    op0 = extract32(insn, 21, 1);
2739 e801de93 Alexander Graf
    bitsize = sf ? 64 : 32;
2740 e801de93 Alexander Graf
2741 e801de93 Alexander Graf
    if (sf != n || op21 || op0 || imm >= bitsize) {
2742 e801de93 Alexander Graf
        unallocated_encoding(s);
2743 e801de93 Alexander Graf
    } else {
2744 e801de93 Alexander Graf
        TCGv_i64 tcg_rd, tcg_rm, tcg_rn;
2745 e801de93 Alexander Graf
2746 e801de93 Alexander Graf
        tcg_rd = cpu_reg(s, rd);
2747 e801de93 Alexander Graf
2748 e801de93 Alexander Graf
        if (imm) {
2749 e801de93 Alexander Graf
            /* OPTME: we can special case rm==rn as a rotate */
2750 e801de93 Alexander Graf
            tcg_rm = read_cpu_reg(s, rm, sf);
2751 e801de93 Alexander Graf
            tcg_rn = read_cpu_reg(s, rn, sf);
2752 e801de93 Alexander Graf
            tcg_gen_shri_i64(tcg_rm, tcg_rm, imm);
2753 e801de93 Alexander Graf
            tcg_gen_shli_i64(tcg_rn, tcg_rn, bitsize - imm);
2754 e801de93 Alexander Graf
            tcg_gen_or_i64(tcg_rd, tcg_rm, tcg_rn);
2755 e801de93 Alexander Graf
            if (!sf) {
2756 e801de93 Alexander Graf
                tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
2757 e801de93 Alexander Graf
            }
2758 e801de93 Alexander Graf
        } else {
2759 e801de93 Alexander Graf
            /* tcg shl_i32/shl_i64 is undefined for 32/64 bit shifts,
2760 e801de93 Alexander Graf
             * so an extract from bit 0 is a special case.
2761 e801de93 Alexander Graf
             */
2762 e801de93 Alexander Graf
            if (sf) {
2763 e801de93 Alexander Graf
                tcg_gen_mov_i64(tcg_rd, cpu_reg(s, rm));
2764 e801de93 Alexander Graf
            } else {
2765 e801de93 Alexander Graf
                tcg_gen_ext32u_i64(tcg_rd, cpu_reg(s, rm));
2766 e801de93 Alexander Graf
            }
2767 e801de93 Alexander Graf
        }
2768 e801de93 Alexander Graf
2769 e801de93 Alexander Graf
    }
2770 ad7ee8a2 Claudio Fontana
}
2771 ad7ee8a2 Claudio Fontana
2772 ad7ee8a2 Claudio Fontana
/* C3.4 Data processing - immediate */
2773 ad7ee8a2 Claudio Fontana
static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
2774 ad7ee8a2 Claudio Fontana
{
2775 ad7ee8a2 Claudio Fontana
    switch (extract32(insn, 23, 6)) {
2776 ad7ee8a2 Claudio Fontana
    case 0x20: case 0x21: /* PC-rel. addressing */
2777 ad7ee8a2 Claudio Fontana
        disas_pc_rel_adr(s, insn);
2778 ad7ee8a2 Claudio Fontana
        break;
2779 ad7ee8a2 Claudio Fontana
    case 0x22: case 0x23: /* Add/subtract (immediate) */
2780 ad7ee8a2 Claudio Fontana
        disas_add_sub_imm(s, insn);
2781 ad7ee8a2 Claudio Fontana
        break;
2782 ad7ee8a2 Claudio Fontana
    case 0x24: /* Logical (immediate) */
2783 ad7ee8a2 Claudio Fontana
        disas_logic_imm(s, insn);
2784 ad7ee8a2 Claudio Fontana
        break;
2785 ad7ee8a2 Claudio Fontana
    case 0x25: /* Move wide (immediate) */
2786 ad7ee8a2 Claudio Fontana
        disas_movw_imm(s, insn);
2787 ad7ee8a2 Claudio Fontana
        break;
2788 ad7ee8a2 Claudio Fontana
    case 0x26: /* Bitfield */
2789 ad7ee8a2 Claudio Fontana
        disas_bitfield(s, insn);
2790 ad7ee8a2 Claudio Fontana
        break;
2791 ad7ee8a2 Claudio Fontana
    case 0x27: /* Extract */
2792 ad7ee8a2 Claudio Fontana
        disas_extract(s, insn);
2793 ad7ee8a2 Claudio Fontana
        break;
2794 ad7ee8a2 Claudio Fontana
    default:
2795 ad7ee8a2 Claudio Fontana
        unallocated_encoding(s);
2796 ad7ee8a2 Claudio Fontana
        break;
2797 ad7ee8a2 Claudio Fontana
    }
2798 ad7ee8a2 Claudio Fontana
}
2799 ad7ee8a2 Claudio Fontana
2800 832ffa1c Alexander Graf
/* Shift a TCGv src by TCGv shift_amount, put result in dst.
2801 832ffa1c Alexander Graf
 * Note that it is the caller's responsibility to ensure that the
2802 832ffa1c Alexander Graf
 * shift amount is in range (ie 0..31 or 0..63) and provide the ARM
2803 832ffa1c Alexander Graf
 * mandated semantics for out of range shifts.
2804 832ffa1c Alexander Graf
 */
2805 832ffa1c Alexander Graf
static void shift_reg(TCGv_i64 dst, TCGv_i64 src, int sf,
2806 832ffa1c Alexander Graf
                      enum a64_shift_type shift_type, TCGv_i64 shift_amount)
2807 832ffa1c Alexander Graf
{
2808 832ffa1c Alexander Graf
    switch (shift_type) {
2809 832ffa1c Alexander Graf
    case A64_SHIFT_TYPE_LSL:
2810 832ffa1c Alexander Graf
        tcg_gen_shl_i64(dst, src, shift_amount);
2811 832ffa1c Alexander Graf
        break;
2812 832ffa1c Alexander Graf
    case A64_SHIFT_TYPE_LSR:
2813 832ffa1c Alexander Graf
        tcg_gen_shr_i64(dst, src, shift_amount);
2814 832ffa1c Alexander Graf
        break;
2815 832ffa1c Alexander Graf
    case A64_SHIFT_TYPE_ASR:
2816 832ffa1c Alexander Graf
        if (!sf) {
2817 832ffa1c Alexander Graf
            tcg_gen_ext32s_i64(dst, src);
2818 832ffa1c Alexander Graf
        }
2819 832ffa1c Alexander Graf
        tcg_gen_sar_i64(dst, sf ? src : dst, shift_amount);
2820 832ffa1c Alexander Graf
        break;
2821 832ffa1c Alexander Graf
    case A64_SHIFT_TYPE_ROR:
2822 832ffa1c Alexander Graf
        if (sf) {
2823 832ffa1c Alexander Graf
            tcg_gen_rotr_i64(dst, src, shift_amount);
2824 832ffa1c Alexander Graf
        } else {
2825 832ffa1c Alexander Graf
            TCGv_i32 t0, t1;
2826 832ffa1c Alexander Graf
            t0 = tcg_temp_new_i32();
2827 832ffa1c Alexander Graf
            t1 = tcg_temp_new_i32();
2828 832ffa1c Alexander Graf
            tcg_gen_trunc_i64_i32(t0, src);
2829 832ffa1c Alexander Graf
            tcg_gen_trunc_i64_i32(t1, shift_amount);
2830 832ffa1c Alexander Graf
            tcg_gen_rotr_i32(t0, t0, t1);
2831 832ffa1c Alexander Graf
            tcg_gen_extu_i32_i64(dst, t0);
2832 832ffa1c Alexander Graf
            tcg_temp_free_i32(t0);
2833 832ffa1c Alexander Graf
            tcg_temp_free_i32(t1);
2834 832ffa1c Alexander Graf
        }
2835 832ffa1c Alexander Graf
        break;
2836 832ffa1c Alexander Graf
    default:
2837 832ffa1c Alexander Graf
        assert(FALSE); /* all shift types should be handled */
2838 832ffa1c Alexander Graf
        break;
2839 832ffa1c Alexander Graf
    }
2840 832ffa1c Alexander Graf
2841 832ffa1c Alexander Graf
    if (!sf) { /* zero extend final result */
2842 832ffa1c Alexander Graf
        tcg_gen_ext32u_i64(dst, dst);
2843 832ffa1c Alexander Graf
    }
2844 832ffa1c Alexander Graf
}
2845 832ffa1c Alexander Graf
2846 832ffa1c Alexander Graf
/* Shift a TCGv src by immediate, put result in dst.
2847 832ffa1c Alexander Graf
 * The shift amount must be in range (this should always be true as the
2848 832ffa1c Alexander Graf
 * relevant instructions will UNDEF on bad shift immediates).
2849 832ffa1c Alexander Graf
 */
2850 832ffa1c Alexander Graf
static void shift_reg_imm(TCGv_i64 dst, TCGv_i64 src, int sf,
2851 832ffa1c Alexander Graf
                          enum a64_shift_type shift_type, unsigned int shift_i)
2852 832ffa1c Alexander Graf
{
2853 832ffa1c Alexander Graf
    assert(shift_i < (sf ? 64 : 32));
2854 832ffa1c Alexander Graf
2855 832ffa1c Alexander Graf
    if (shift_i == 0) {
2856 832ffa1c Alexander Graf
        tcg_gen_mov_i64(dst, src);
2857 832ffa1c Alexander Graf
    } else {
2858 832ffa1c Alexander Graf
        TCGv_i64 shift_const;
2859 832ffa1c Alexander Graf
2860 832ffa1c Alexander Graf
        shift_const = tcg_const_i64(shift_i);
2861 832ffa1c Alexander Graf
        shift_reg(dst, src, sf, shift_type, shift_const);
2862 832ffa1c Alexander Graf
        tcg_temp_free_i64(shift_const);
2863 832ffa1c Alexander Graf
    }
2864 832ffa1c Alexander Graf
}
2865 832ffa1c Alexander Graf
2866 832ffa1c Alexander Graf
/* C3.5.10 Logical (shifted register)
2867 832ffa1c Alexander Graf
 *   31  30 29 28       24 23   22 21  20  16 15    10 9    5 4    0
2868 832ffa1c Alexander Graf
 * +----+-----+-----------+-------+---+------+--------+------+------+
2869 832ffa1c Alexander Graf
 * | sf | opc | 0 1 0 1 0 | shift | N |  Rm  |  imm6  |  Rn  |  Rd  |
2870 832ffa1c Alexander Graf
 * +----+-----+-----------+-------+---+------+--------+------+------+
2871 832ffa1c Alexander Graf
 */
2872 ad7ee8a2 Claudio Fontana
static void disas_logic_reg(DisasContext *s, uint32_t insn)
2873 ad7ee8a2 Claudio Fontana
{
2874 832ffa1c Alexander Graf
    TCGv_i64 tcg_rd, tcg_rn, tcg_rm;
2875 832ffa1c Alexander Graf
    unsigned int sf, opc, shift_type, invert, rm, shift_amount, rn, rd;
2876 832ffa1c Alexander Graf
2877 832ffa1c Alexander Graf
    sf = extract32(insn, 31, 1);
2878 832ffa1c Alexander Graf
    opc = extract32(insn, 29, 2);
2879 832ffa1c Alexander Graf
    shift_type = extract32(insn, 22, 2);
2880 832ffa1c Alexander Graf
    invert = extract32(insn, 21, 1);
2881 832ffa1c Alexander Graf
    rm = extract32(insn, 16, 5);
2882 832ffa1c Alexander Graf
    shift_amount = extract32(insn, 10, 6);
2883 832ffa1c Alexander Graf
    rn = extract32(insn, 5, 5);
2884 832ffa1c Alexander Graf
    rd = extract32(insn, 0, 5);
2885 832ffa1c Alexander Graf
2886 832ffa1c Alexander Graf
    if (!sf && (shift_amount & (1 << 5))) {
2887 832ffa1c Alexander Graf
        unallocated_encoding(s);
2888 832ffa1c Alexander Graf
        return;
2889 832ffa1c Alexander Graf
    }
2890 832ffa1c Alexander Graf
2891 832ffa1c Alexander Graf
    tcg_rd = cpu_reg(s, rd);
2892 832ffa1c Alexander Graf
2893 832ffa1c Alexander Graf
    if (opc == 1 && shift_amount == 0 && shift_type == 0 && rn == 31) {
2894 832ffa1c Alexander Graf
        /* Unshifted ORR and ORN with WZR/XZR is the standard encoding for
2895 832ffa1c Alexander Graf
         * register-register MOV and MVN, so it is worth special casing.
2896 832ffa1c Alexander Graf
         */
2897 832ffa1c Alexander Graf
        tcg_rm = cpu_reg(s, rm);
2898 832ffa1c Alexander Graf
        if (invert) {
2899 832ffa1c Alexander Graf
            tcg_gen_not_i64(tcg_rd, tcg_rm);
2900 832ffa1c Alexander Graf
            if (!sf) {
2901 832ffa1c Alexander Graf
                tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
2902 832ffa1c Alexander Graf
            }
2903 832ffa1c Alexander Graf
        } else {
2904 832ffa1c Alexander Graf
            if (sf) {
2905 832ffa1c Alexander Graf
                tcg_gen_mov_i64(tcg_rd, tcg_rm);
2906 832ffa1c Alexander Graf
            } else {
2907 832ffa1c Alexander Graf
                tcg_gen_ext32u_i64(tcg_rd, tcg_rm);
2908 832ffa1c Alexander Graf
            }
2909 832ffa1c Alexander Graf
        }
2910 832ffa1c Alexander Graf
        return;
2911 832ffa1c Alexander Graf
    }
2912 832ffa1c Alexander Graf
2913 832ffa1c Alexander Graf
    tcg_rm = read_cpu_reg(s, rm, sf);
2914 832ffa1c Alexander Graf
2915 832ffa1c Alexander Graf
    if (shift_amount) {
2916 832ffa1c Alexander Graf
        shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, shift_amount);
2917 832ffa1c Alexander Graf
    }
2918 832ffa1c Alexander Graf
2919 832ffa1c Alexander Graf
    tcg_rn = cpu_reg(s, rn);
2920 832ffa1c Alexander Graf
2921 832ffa1c Alexander Graf
    switch (opc | (invert << 2)) {
2922 832ffa1c Alexander Graf
    case 0: /* AND */
2923 832ffa1c Alexander Graf
    case 3: /* ANDS */
2924 832ffa1c Alexander Graf
        tcg_gen_and_i64(tcg_rd, tcg_rn, tcg_rm);
2925 832ffa1c Alexander Graf
        break;
2926 832ffa1c Alexander Graf
    case 1: /* ORR */
2927 832ffa1c Alexander Graf
        tcg_gen_or_i64(tcg_rd, tcg_rn, tcg_rm);
2928 832ffa1c Alexander Graf
        break;
2929 832ffa1c Alexander Graf
    case 2: /* EOR */
2930 832ffa1c Alexander Graf
        tcg_gen_xor_i64(tcg_rd, tcg_rn, tcg_rm);
2931 832ffa1c Alexander Graf
        break;
2932 832ffa1c Alexander Graf
    case 4: /* BIC */
2933 832ffa1c Alexander Graf
    case 7: /* BICS */
2934 832ffa1c Alexander Graf
        tcg_gen_andc_i64(tcg_rd, tcg_rn, tcg_rm);
2935 832ffa1c Alexander Graf
        break;
2936 832ffa1c Alexander Graf
    case 5: /* ORN */
2937 832ffa1c Alexander Graf
        tcg_gen_orc_i64(tcg_rd, tcg_rn, tcg_rm);
2938 832ffa1c Alexander Graf
        break;
2939 832ffa1c Alexander Graf
    case 6: /* EON */
2940 832ffa1c Alexander Graf
        tcg_gen_eqv_i64(tcg_rd, tcg_rn, tcg_rm);
2941 832ffa1c Alexander Graf
        break;
2942 832ffa1c Alexander Graf
    default:
2943 832ffa1c Alexander Graf
        assert(FALSE);
2944 832ffa1c Alexander Graf
        break;
2945 832ffa1c Alexander Graf
    }
2946 832ffa1c Alexander Graf
2947 832ffa1c Alexander Graf
    if (!sf) {
2948 832ffa1c Alexander Graf
        tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
2949 832ffa1c Alexander Graf
    }
2950 832ffa1c Alexander Graf
2951 832ffa1c Alexander Graf
    if (opc == 3) {
2952 832ffa1c Alexander Graf
        gen_logic_CC(sf, tcg_rd);
2953 832ffa1c Alexander Graf
    }
2954 ad7ee8a2 Claudio Fontana
}
2955 ad7ee8a2 Claudio Fontana
2956 b0ff21b4 Alex Bennée
/*
2957 b0ff21b4 Alex Bennée
 * C3.5.1 Add/subtract (extended register)
2958 b0ff21b4 Alex Bennée
 *
2959 b0ff21b4 Alex Bennée
 *  31|30|29|28       24|23 22|21|20   16|15  13|12  10|9  5|4  0|
2960 b0ff21b4 Alex Bennée
 * +--+--+--+-----------+-----+--+-------+------+------+----+----+
2961 b0ff21b4 Alex Bennée
 * |sf|op| S| 0 1 0 1 1 | opt | 1|  Rm   |option| imm3 | Rn | Rd |
2962 b0ff21b4 Alex Bennée
 * +--+--+--+-----------+-----+--+-------+------+------+----+----+
2963 b0ff21b4 Alex Bennée
 *
2964 b0ff21b4 Alex Bennée
 *  sf: 0 -> 32bit, 1 -> 64bit
2965 b0ff21b4 Alex Bennée
 *  op: 0 -> add  , 1 -> sub
2966 b0ff21b4 Alex Bennée
 *   S: 1 -> set flags
2967 b0ff21b4 Alex Bennée
 * opt: 00
2968 b0ff21b4 Alex Bennée
 * option: extension type (see DecodeRegExtend)
2969 b0ff21b4 Alex Bennée
 * imm3: optional shift to Rm
2970 b0ff21b4 Alex Bennée
 *
2971 b0ff21b4 Alex Bennée
 * Rd = Rn + LSL(extend(Rm), amount)
2972 b0ff21b4 Alex Bennée
 */
2973 ad7ee8a2 Claudio Fontana
static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
2974 ad7ee8a2 Claudio Fontana
{
2975 b0ff21b4 Alex Bennée
    int rd = extract32(insn, 0, 5);
2976 b0ff21b4 Alex Bennée
    int rn = extract32(insn, 5, 5);
2977 b0ff21b4 Alex Bennée
    int imm3 = extract32(insn, 10, 3);
2978 b0ff21b4 Alex Bennée
    int option = extract32(insn, 13, 3);
2979 b0ff21b4 Alex Bennée
    int rm = extract32(insn, 16, 5);
2980 b0ff21b4 Alex Bennée
    bool setflags = extract32(insn, 29, 1);
2981 b0ff21b4 Alex Bennée
    bool sub_op = extract32(insn, 30, 1);
2982 b0ff21b4 Alex Bennée
    bool sf = extract32(insn, 31, 1);
2983 b0ff21b4 Alex Bennée
2984 b0ff21b4 Alex Bennée
    TCGv_i64 tcg_rm, tcg_rn; /* temps */
2985 b0ff21b4 Alex Bennée
    TCGv_i64 tcg_rd;
2986 b0ff21b4 Alex Bennée
    TCGv_i64 tcg_result;
2987 b0ff21b4 Alex Bennée
2988 b0ff21b4 Alex Bennée
    if (imm3 > 4) {
2989 b0ff21b4 Alex Bennée
        unallocated_encoding(s);
2990 b0ff21b4 Alex Bennée
        return;
2991 b0ff21b4 Alex Bennée
    }
2992 b0ff21b4 Alex Bennée
2993 b0ff21b4 Alex Bennée
    /* non-flag setting ops may use SP */
2994 b0ff21b4 Alex Bennée
    if (!setflags) {
2995 b0ff21b4 Alex Bennée
        tcg_rn = read_cpu_reg_sp(s, rn, sf);
2996 b0ff21b4 Alex Bennée
        tcg_rd = cpu_reg_sp(s, rd);
2997 b0ff21b4 Alex Bennée
    } else {
2998 b0ff21b4 Alex Bennée
        tcg_rn = read_cpu_reg(s, rn, sf);
2999 b0ff21b4 Alex Bennée
        tcg_rd = cpu_reg(s, rd);
3000 b0ff21b4 Alex Bennée
    }
3001 b0ff21b4 Alex Bennée
3002 b0ff21b4 Alex Bennée
    tcg_rm = read_cpu_reg(s, rm, sf);
3003 b0ff21b4 Alex Bennée
    ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3);
3004 b0ff21b4 Alex Bennée
3005 b0ff21b4 Alex Bennée
    tcg_result = tcg_temp_new_i64();
3006 b0ff21b4 Alex Bennée
3007 b0ff21b4 Alex Bennée
    if (!setflags) {
3008 b0ff21b4 Alex Bennée
        if (sub_op) {
3009 b0ff21b4 Alex Bennée
            tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
3010 b0ff21b4 Alex Bennée
        } else {
3011 b0ff21b4 Alex Bennée
            tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
3012 b0ff21b4 Alex Bennée
        }
3013 b0ff21b4 Alex Bennée
    } else {
3014 b0ff21b4 Alex Bennée
        if (sub_op) {
3015 b0ff21b4 Alex Bennée
            gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
3016 b0ff21b4 Alex Bennée
        } else {
3017 b0ff21b4 Alex Bennée
            gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
3018 b0ff21b4 Alex Bennée
        }
3019 b0ff21b4 Alex Bennée
    }
3020 b0ff21b4 Alex Bennée
3021 b0ff21b4 Alex Bennée
    if (sf) {
3022 b0ff21b4 Alex Bennée
        tcg_gen_mov_i64(tcg_rd, tcg_result);
3023 b0ff21b4 Alex Bennée
    } else {
3024 b0ff21b4 Alex Bennée
        tcg_gen_ext32u_i64(tcg_rd, tcg_result);
3025 b0ff21b4 Alex Bennée
    }
3026 b0ff21b4 Alex Bennée
3027 b0ff21b4 Alex Bennée
    tcg_temp_free_i64(tcg_result);
3028 ad7ee8a2 Claudio Fontana
}
3029 ad7ee8a2 Claudio Fontana
3030 b0ff21b4 Alex Bennée
/*
3031 b0ff21b4 Alex Bennée
 * C3.5.2 Add/subtract (shifted register)
3032 b0ff21b4 Alex Bennée
 *
3033 b0ff21b4 Alex Bennée
 *  31 30 29 28       24 23 22 21 20   16 15     10 9    5 4    0
3034 b0ff21b4 Alex Bennée
 * +--+--+--+-----------+-----+--+-------+---------+------+------+
3035 b0ff21b4 Alex Bennée
 * |sf|op| S| 0 1 0 1 1 |shift| 0|  Rm   |  imm6   |  Rn  |  Rd  |
3036 b0ff21b4 Alex Bennée
 * +--+--+--+-----------+-----+--+-------+---------+------+------+
3037 b0ff21b4 Alex Bennée
 *
3038 b0ff21b4 Alex Bennée
 *    sf: 0 -> 32bit, 1 -> 64bit
3039 b0ff21b4 Alex Bennée
 *    op: 0 -> add  , 1 -> sub
3040 b0ff21b4 Alex Bennée
 *     S: 1 -> set flags
3041 b0ff21b4 Alex Bennée
 * shift: 00 -> LSL, 01 -> LSR, 10 -> ASR, 11 -> RESERVED
3042 b0ff21b4 Alex Bennée
 *  imm6: Shift amount to apply to Rm before the add/sub
3043 b0ff21b4 Alex Bennée
 */
3044 ad7ee8a2 Claudio Fontana
static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
3045 ad7ee8a2 Claudio Fontana
{
3046 b0ff21b4 Alex Bennée
    int rd = extract32(insn, 0, 5);
3047 b0ff21b4 Alex Bennée
    int rn = extract32(insn, 5, 5);
3048 b0ff21b4 Alex Bennée
    int imm6 = extract32(insn, 10, 6);
3049 b0ff21b4 Alex Bennée
    int rm = extract32(insn, 16, 5);
3050 b0ff21b4 Alex Bennée
    int shift_type = extract32(insn, 22, 2);
3051 b0ff21b4 Alex Bennée
    bool setflags = extract32(insn, 29, 1);
3052 b0ff21b4 Alex Bennée
    bool sub_op = extract32(insn, 30, 1);
3053 b0ff21b4 Alex Bennée
    bool sf = extract32(insn, 31, 1);
3054 b0ff21b4 Alex Bennée
3055 b0ff21b4 Alex Bennée
    TCGv_i64 tcg_rd = cpu_reg(s, rd);
3056 b0ff21b4 Alex Bennée
    TCGv_i64 tcg_rn, tcg_rm;
3057 b0ff21b4 Alex Bennée
    TCGv_i64 tcg_result;
3058 b0ff21b4 Alex Bennée
3059 b0ff21b4 Alex Bennée
    if ((shift_type == 3) || (!sf && (imm6 > 31))) {
3060 b0ff21b4 Alex Bennée
        unallocated_encoding(s);
3061 b0ff21b4 Alex Bennée
        return;
3062 b0ff21b4 Alex Bennée
    }
3063 b0ff21b4 Alex Bennée
3064 b0ff21b4 Alex Bennée
    tcg_rn = read_cpu_reg(s, rn, sf);
3065 b0ff21b4 Alex Bennée
    tcg_rm = read_cpu_reg(s, rm, sf);
3066 b0ff21b4 Alex Bennée
3067 b0ff21b4 Alex Bennée
    shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6);
3068 b0ff21b4 Alex Bennée
3069 b0ff21b4 Alex Bennée
    tcg_result = tcg_temp_new_i64();
3070 b0ff21b4 Alex Bennée
3071 b0ff21b4 Alex Bennée
    if (!setflags) {
3072 b0ff21b4 Alex Bennée
        if (sub_op) {
3073 b0ff21b4 Alex Bennée
            tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
3074 b0ff21b4 Alex Bennée
        } else {
3075 b0ff21b4 Alex Bennée
            tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
3076 b0ff21b4 Alex Bennée
        }
3077 b0ff21b4 Alex Bennée
    } else {
3078 b0ff21b4 Alex Bennée
        if (sub_op) {
3079 b0ff21b4 Alex Bennée
            gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
3080 b0ff21b4 Alex Bennée
        } else {
3081 b0ff21b4 Alex Bennée
            gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
3082 b0ff21b4 Alex Bennée
        }
3083 b0ff21b4 Alex Bennée
    }
3084 b0ff21b4 Alex Bennée
3085 b0ff21b4 Alex Bennée
    if (sf) {
3086 b0ff21b4 Alex Bennée
        tcg_gen_mov_i64(tcg_rd, tcg_result);
3087 b0ff21b4 Alex Bennée
    } else {
3088 b0ff21b4 Alex Bennée
        tcg_gen_ext32u_i64(tcg_rd, tcg_result);
3089 b0ff21b4 Alex Bennée
    }
3090 b0ff21b4 Alex Bennée
3091 b0ff21b4 Alex Bennée
    tcg_temp_free_i64(tcg_result);
3092 ad7ee8a2 Claudio Fontana
}
3093 ad7ee8a2 Claudio Fontana
3094 52c8b9af Alexander Graf
/* C3.5.9 Data-processing (3 source)
3095 52c8b9af Alexander Graf

3096 52c8b9af Alexander Graf
   31 30  29 28       24 23 21  20  16  15  14  10 9    5 4    0
3097 52c8b9af Alexander Graf
  +--+------+-----------+------+------+----+------+------+------+
3098 52c8b9af Alexander Graf
  |sf| op54 | 1 1 0 1 1 | op31 |  Rm  | o0 |  Ra  |  Rn  |  Rd  |
3099 52c8b9af Alexander Graf
  +--+------+-----------+------+------+----+------+------+------+
3100 52c8b9af Alexander Graf

3101 52c8b9af Alexander Graf
 */
3102 ad7ee8a2 Claudio Fontana
static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
3103 ad7ee8a2 Claudio Fontana
{
3104 52c8b9af Alexander Graf
    int rd = extract32(insn, 0, 5);
3105 52c8b9af Alexander Graf
    int rn = extract32(insn, 5, 5);
3106 52c8b9af Alexander Graf
    int ra = extract32(insn, 10, 5);
3107 52c8b9af Alexander Graf
    int rm = extract32(insn, 16, 5);
3108 52c8b9af Alexander Graf
    int op_id = (extract32(insn, 29, 3) << 4) |
3109 52c8b9af Alexander Graf
        (extract32(insn, 21, 3) << 1) |
3110 52c8b9af Alexander Graf
        extract32(insn, 15, 1);
3111 52c8b9af Alexander Graf
    bool sf = extract32(insn, 31, 1);
3112 52c8b9af Alexander Graf
    bool is_sub = extract32(op_id, 0, 1);
3113 52c8b9af Alexander Graf
    bool is_high = extract32(op_id, 2, 1);
3114 52c8b9af Alexander Graf
    bool is_signed = false;
3115 52c8b9af Alexander Graf
    TCGv_i64 tcg_op1;
3116 52c8b9af Alexander Graf
    TCGv_i64 tcg_op2;
3117 52c8b9af Alexander Graf
    TCGv_i64 tcg_tmp;
3118 52c8b9af Alexander Graf
3119 52c8b9af Alexander Graf
    /* Note that op_id is sf:op54:op31:o0 so it includes the 32/64 size flag */
3120 52c8b9af Alexander Graf
    switch (op_id) {
3121 52c8b9af Alexander Graf
    case 0x42: /* SMADDL */
3122 52c8b9af Alexander Graf
    case 0x43: /* SMSUBL */
3123 52c8b9af Alexander Graf
    case 0x44: /* SMULH */
3124 52c8b9af Alexander Graf
        is_signed = true;
3125 52c8b9af Alexander Graf
        break;
3126 52c8b9af Alexander Graf
    case 0x0: /* MADD (32bit) */
3127 52c8b9af Alexander Graf
    case 0x1: /* MSUB (32bit) */
3128 52c8b9af Alexander Graf
    case 0x40: /* MADD (64bit) */
3129 52c8b9af Alexander Graf
    case 0x41: /* MSUB (64bit) */
3130 52c8b9af Alexander Graf
    case 0x4a: /* UMADDL */
3131 52c8b9af Alexander Graf
    case 0x4b: /* UMSUBL */
3132 52c8b9af Alexander Graf
    case 0x4c: /* UMULH */
3133 52c8b9af Alexander Graf
        break;
3134 52c8b9af Alexander Graf
    default:
3135 52c8b9af Alexander Graf
        unallocated_encoding(s);
3136 52c8b9af Alexander Graf
        return;
3137 52c8b9af Alexander Graf
    }
3138 52c8b9af Alexander Graf
3139 52c8b9af Alexander Graf
    if (is_high) {
3140 52c8b9af Alexander Graf
        TCGv_i64 low_bits = tcg_temp_new_i64(); /* low bits discarded */
3141 52c8b9af Alexander Graf
        TCGv_i64 tcg_rd = cpu_reg(s, rd);
3142 52c8b9af Alexander Graf
        TCGv_i64 tcg_rn = cpu_reg(s, rn);
3143 52c8b9af Alexander Graf
        TCGv_i64 tcg_rm = cpu_reg(s, rm);
3144 52c8b9af Alexander Graf
3145 52c8b9af Alexander Graf
        if (is_signed) {
3146 52c8b9af Alexander Graf
            tcg_gen_muls2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
3147 52c8b9af Alexander Graf
        } else {
3148 52c8b9af Alexander Graf
            tcg_gen_mulu2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
3149 52c8b9af Alexander Graf
        }
3150 52c8b9af Alexander Graf
3151 52c8b9af Alexander Graf
        tcg_temp_free_i64(low_bits);
3152 52c8b9af Alexander Graf
        return;
3153 52c8b9af Alexander Graf
    }
3154 52c8b9af Alexander Graf
3155 52c8b9af Alexander Graf
    tcg_op1 = tcg_temp_new_i64();
3156 52c8b9af Alexander Graf
    tcg_op2 = tcg_temp_new_i64();
3157 52c8b9af Alexander Graf
    tcg_tmp = tcg_temp_new_i64();
3158 52c8b9af Alexander Graf
3159 52c8b9af Alexander Graf
    if (op_id < 0x42) {
3160 52c8b9af Alexander Graf
        tcg_gen_mov_i64(tcg_op1, cpu_reg(s, rn));
3161 52c8b9af Alexander Graf
        tcg_gen_mov_i64(tcg_op2, cpu_reg(s, rm));
3162 52c8b9af Alexander Graf
    } else {
3163 52c8b9af Alexander Graf
        if (is_signed) {
3164 52c8b9af Alexander Graf
            tcg_gen_ext32s_i64(tcg_op1, cpu_reg(s, rn));
3165 52c8b9af Alexander Graf
            tcg_gen_ext32s_i64(tcg_op2, cpu_reg(s, rm));
3166 52c8b9af Alexander Graf
        } else {
3167 52c8b9af Alexander Graf
            tcg_gen_ext32u_i64(tcg_op1, cpu_reg(s, rn));
3168 52c8b9af Alexander Graf
            tcg_gen_ext32u_i64(tcg_op2, cpu_reg(s, rm));
3169 52c8b9af Alexander Graf
        }
3170 52c8b9af Alexander Graf
    }
3171 52c8b9af Alexander Graf
3172 52c8b9af Alexander Graf
    if (ra == 31 && !is_sub) {
3173 52c8b9af Alexander Graf
        /* Special-case MADD with rA == XZR; it is the standard MUL alias */
3174 52c8b9af Alexander Graf
        tcg_gen_mul_i64(cpu_reg(s, rd), tcg_op1, tcg_op2);
3175 52c8b9af Alexander Graf
    } else {
3176 52c8b9af Alexander Graf
        tcg_gen_mul_i64(tcg_tmp, tcg_op1, tcg_op2);
3177 52c8b9af Alexander Graf
        if (is_sub) {
3178 52c8b9af Alexander Graf
            tcg_gen_sub_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
3179 52c8b9af Alexander Graf
        } else {
3180 52c8b9af Alexander Graf
            tcg_gen_add_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
3181 52c8b9af Alexander Graf
        }
3182 52c8b9af Alexander Graf
    }
3183 52c8b9af Alexander Graf
3184 52c8b9af Alexander Graf
    if (!sf) {
3185 52c8b9af Alexander Graf
        tcg_gen_ext32u_i64(cpu_reg(s, rd), cpu_reg(s, rd));
3186 52c8b9af Alexander Graf
    }
3187 52c8b9af Alexander Graf
3188 52c8b9af Alexander Graf
    tcg_temp_free_i64(tcg_op1);
3189 52c8b9af Alexander Graf
    tcg_temp_free_i64(tcg_op2);
3190 52c8b9af Alexander Graf
    tcg_temp_free_i64(tcg_tmp);
3191 ad7ee8a2 Claudio Fontana
}
3192 ad7ee8a2 Claudio Fontana
3193 643dbb07 Claudio Fontana
/* C3.5.3 - Add/subtract (with carry)
3194 643dbb07 Claudio Fontana
 *  31 30 29 28 27 26 25 24 23 22 21  20  16  15   10  9    5 4   0
3195 643dbb07 Claudio Fontana
 * +--+--+--+------------------------+------+---------+------+-----+
3196 643dbb07 Claudio Fontana
 * |sf|op| S| 1  1  0  1  0  0  0  0 |  rm  | opcode2 |  Rn  |  Rd |
3197 643dbb07 Claudio Fontana
 * +--+--+--+------------------------+------+---------+------+-----+
3198 643dbb07 Claudio Fontana
 *                                            [000000]
3199 643dbb07 Claudio Fontana
 */
3200 643dbb07 Claudio Fontana
3201 ad7ee8a2 Claudio Fontana
static void disas_adc_sbc(DisasContext *s, uint32_t insn)
3202 ad7ee8a2 Claudio Fontana
{
3203 643dbb07 Claudio Fontana
    unsigned int sf, op, setflags, rm, rn, rd;
3204 643dbb07 Claudio Fontana
    TCGv_i64 tcg_y, tcg_rn, tcg_rd;
3205 643dbb07 Claudio Fontana
3206 643dbb07 Claudio Fontana
    if (extract32(insn, 10, 6) != 0) {
3207 643dbb07 Claudio Fontana
        unallocated_encoding(s);
3208 643dbb07 Claudio Fontana
        return;
3209 643dbb07 Claudio Fontana
    }
3210 643dbb07 Claudio Fontana
3211 643dbb07 Claudio Fontana
    sf = extract32(insn, 31, 1);
3212 643dbb07 Claudio Fontana
    op = extract32(insn, 30, 1);
3213 643dbb07 Claudio Fontana
    setflags = extract32(insn, 29, 1);
3214 643dbb07 Claudio Fontana
    rm = extract32(insn, 16, 5);
3215 643dbb07 Claudio Fontana
    rn = extract32(insn, 5, 5);
3216 643dbb07 Claudio Fontana
    rd = extract32(insn, 0, 5);
3217 643dbb07 Claudio Fontana
3218 643dbb07 Claudio Fontana
    tcg_rd = cpu_reg(s, rd);
3219 643dbb07 Claudio Fontana
    tcg_rn = cpu_reg(s, rn);
3220 643dbb07 Claudio Fontana
3221 643dbb07 Claudio Fontana
    if (op) {
3222 643dbb07 Claudio Fontana
        tcg_y = new_tmp_a64(s);
3223 643dbb07 Claudio Fontana
        tcg_gen_not_i64(tcg_y, cpu_reg(s, rm));
3224 643dbb07 Claudio Fontana
    } else {
3225 643dbb07 Claudio Fontana
        tcg_y = cpu_reg(s, rm);
3226 643dbb07 Claudio Fontana
    }
3227 643dbb07 Claudio Fontana
3228 643dbb07 Claudio Fontana
    if (setflags) {
3229 643dbb07 Claudio Fontana
        gen_adc_CC(sf, tcg_rd, tcg_rn, tcg_y);
3230 643dbb07 Claudio Fontana
    } else {
3231 643dbb07 Claudio Fontana
        gen_adc(sf, tcg_rd, tcg_rn, tcg_y);
3232 643dbb07 Claudio Fontana
    }
3233 ad7ee8a2 Claudio Fontana
}
3234 ad7ee8a2 Claudio Fontana
3235 750813cf Claudio Fontana
/* C3.5.4 - C3.5.5 Conditional compare (immediate / register)
3236 750813cf Claudio Fontana
 *  31 30 29 28 27 26 25 24 23 22 21  20    16 15  12  11  10  9   5  4 3   0
3237 750813cf Claudio Fontana
 * +--+--+--+------------------------+--------+------+----+--+------+--+-----+
3238 750813cf Claudio Fontana
 * |sf|op| S| 1  1  0  1  0  0  1  0 |imm5/rm | cond |i/r |o2|  Rn  |o3|nzcv |
3239 750813cf Claudio Fontana
 * +--+--+--+------------------------+--------+------+----+--+------+--+-----+
3240 750813cf Claudio Fontana
 *        [1]                             y                [0]       [0]
3241 750813cf Claudio Fontana
 */
3242 750813cf Claudio Fontana
static void disas_cc(DisasContext *s, uint32_t insn)
3243 ad7ee8a2 Claudio Fontana
{
3244 750813cf Claudio Fontana
    unsigned int sf, op, y, cond, rn, nzcv, is_imm;
3245 750813cf Claudio Fontana
    int label_continue = -1;
3246 750813cf Claudio Fontana
    TCGv_i64 tcg_tmp, tcg_y, tcg_rn;
3247 ad7ee8a2 Claudio Fontana
3248 750813cf Claudio Fontana
    if (!extract32(insn, 29, 1)) {
3249 750813cf Claudio Fontana
        unallocated_encoding(s);
3250 750813cf Claudio Fontana
        return;
3251 750813cf Claudio Fontana
    }
3252 750813cf Claudio Fontana
    if (insn & (1 << 10 | 1 << 4)) {
3253 750813cf Claudio Fontana
        unallocated_encoding(s);
3254 750813cf Claudio Fontana
        return;
3255 750813cf Claudio Fontana
    }
3256 750813cf Claudio Fontana
    sf = extract32(insn, 31, 1);
3257 750813cf Claudio Fontana
    op = extract32(insn, 30, 1);
3258 750813cf Claudio Fontana
    is_imm = extract32(insn, 11, 1);
3259 750813cf Claudio Fontana
    y = extract32(insn, 16, 5); /* y = rm (reg) or imm5 (imm) */
3260 750813cf Claudio Fontana
    cond = extract32(insn, 12, 4);
3261 750813cf Claudio Fontana
    rn = extract32(insn, 5, 5);
3262 750813cf Claudio Fontana
    nzcv = extract32(insn, 0, 4);
3263 750813cf Claudio Fontana
3264 750813cf Claudio Fontana
    if (cond < 0x0e) { /* not always */
3265 750813cf Claudio Fontana
        int label_match = gen_new_label();
3266 750813cf Claudio Fontana
        label_continue = gen_new_label();
3267 750813cf Claudio Fontana
        arm_gen_test_cc(cond, label_match);
3268 750813cf Claudio Fontana
        /* nomatch: */
3269 750813cf Claudio Fontana
        tcg_tmp = tcg_temp_new_i64();
3270 750813cf Claudio Fontana
        tcg_gen_movi_i64(tcg_tmp, nzcv << 28);
3271 750813cf Claudio Fontana
        gen_set_nzcv(tcg_tmp);
3272 750813cf Claudio Fontana
        tcg_temp_free_i64(tcg_tmp);
3273 750813cf Claudio Fontana
        tcg_gen_br(label_continue);
3274 750813cf Claudio Fontana
        gen_set_label(label_match);
3275 750813cf Claudio Fontana
    }
3276 750813cf Claudio Fontana
    /* match, or condition is always */
3277 750813cf Claudio Fontana
    if (is_imm) {
3278 750813cf Claudio Fontana
        tcg_y = new_tmp_a64(s);
3279 750813cf Claudio Fontana
        tcg_gen_movi_i64(tcg_y, y);
3280 750813cf Claudio Fontana
    } else {
3281 750813cf Claudio Fontana
        tcg_y = cpu_reg(s, y);
3282 750813cf Claudio Fontana
    }
3283 750813cf Claudio Fontana
    tcg_rn = cpu_reg(s, rn);
3284 750813cf Claudio Fontana
3285 750813cf Claudio Fontana
    tcg_tmp = tcg_temp_new_i64();
3286 750813cf Claudio Fontana
    if (op) {
3287 750813cf Claudio Fontana
        gen_sub_CC(sf, tcg_tmp, tcg_rn, tcg_y);
3288 750813cf Claudio Fontana
    } else {
3289 750813cf Claudio Fontana
        gen_add_CC(sf, tcg_tmp, tcg_rn, tcg_y);
3290 750813cf Claudio Fontana
    }
3291 750813cf Claudio Fontana
    tcg_temp_free_i64(tcg_tmp);
3292 750813cf Claudio Fontana
3293 750813cf Claudio Fontana
    if (cond < 0x0e) { /* continue */
3294 750813cf Claudio Fontana
        gen_set_label(label_continue);
3295 750813cf Claudio Fontana
    }
3296 ad7ee8a2 Claudio Fontana
}
3297 ad7ee8a2 Claudio Fontana
3298 e952d8c7 Claudio Fontana
/* C3.5.6 Conditional select
3299 e952d8c7 Claudio Fontana
 *   31   30  29  28             21 20  16 15  12 11 10 9    5 4    0
3300 e952d8c7 Claudio Fontana
 * +----+----+---+-----------------+------+------+-----+------+------+
3301 e952d8c7 Claudio Fontana
 * | sf | op | S | 1 1 0 1 0 1 0 0 |  Rm  | cond | op2 |  Rn  |  Rd  |
3302 e952d8c7 Claudio Fontana
 * +----+----+---+-----------------+------+------+-----+------+------+
3303 e952d8c7 Claudio Fontana
 */
3304 ad7ee8a2 Claudio Fontana
static void disas_cond_select(DisasContext *s, uint32_t insn)
3305 ad7ee8a2 Claudio Fontana
{
3306 e952d8c7 Claudio Fontana
    unsigned int sf, else_inv, rm, cond, else_inc, rn, rd;
3307 e952d8c7 Claudio Fontana
    TCGv_i64 tcg_rd, tcg_src;
3308 e952d8c7 Claudio Fontana
3309 e952d8c7 Claudio Fontana
    if (extract32(insn, 29, 1) || extract32(insn, 11, 1)) {
3310 e952d8c7 Claudio Fontana
        /* S == 1 or op2<1> == 1 */
3311 e952d8c7 Claudio Fontana
        unallocated_encoding(s);
3312 e952d8c7 Claudio Fontana
        return;
3313 e952d8c7 Claudio Fontana
    }
3314 e952d8c7 Claudio Fontana
    sf = extract32(insn, 31, 1);
3315 e952d8c7 Claudio Fontana
    else_inv = extract32(insn, 30, 1);
3316 e952d8c7 Claudio Fontana
    rm = extract32(insn, 16, 5);
3317 e952d8c7 Claudio Fontana
    cond = extract32(insn, 12, 4);
3318 e952d8c7 Claudio Fontana
    else_inc = extract32(insn, 10, 1);
3319 e952d8c7 Claudio Fontana
    rn = extract32(insn, 5, 5);
3320 e952d8c7 Claudio Fontana
    rd = extract32(insn, 0, 5);
3321 e952d8c7 Claudio Fontana
3322 e952d8c7 Claudio Fontana
    if (rd == 31) {
3323 e952d8c7 Claudio Fontana
        /* silly no-op write; until we use movcond we must special-case
3324 e952d8c7 Claudio Fontana
         * this to avoid a dead temporary across basic blocks.
3325 e952d8c7 Claudio Fontana
         */
3326 e952d8c7 Claudio Fontana
        return;
3327 e952d8c7 Claudio Fontana
    }
3328 e952d8c7 Claudio Fontana
3329 e952d8c7 Claudio Fontana
    tcg_rd = cpu_reg(s, rd);
3330 e952d8c7 Claudio Fontana
3331 e952d8c7 Claudio Fontana
    if (cond >= 0x0e) { /* condition "always" */
3332 e952d8c7 Claudio Fontana
        tcg_src = read_cpu_reg(s, rn, sf);
3333 e952d8c7 Claudio Fontana
        tcg_gen_mov_i64(tcg_rd, tcg_src);
3334 e952d8c7 Claudio Fontana
    } else {
3335 e952d8c7 Claudio Fontana
        /* OPTME: we could use movcond here, at the cost of duplicating
3336 e952d8c7 Claudio Fontana
         * a lot of the arm_gen_test_cc() logic.
3337 e952d8c7 Claudio Fontana
         */
3338 e952d8c7 Claudio Fontana
        int label_match = gen_new_label();
3339 e952d8c7 Claudio Fontana
        int label_continue = gen_new_label();
3340 e952d8c7 Claudio Fontana
3341 e952d8c7 Claudio Fontana
        arm_gen_test_cc(cond, label_match);
3342 e952d8c7 Claudio Fontana
        /* nomatch: */
3343 e952d8c7 Claudio Fontana
        tcg_src = cpu_reg(s, rm);
3344 e952d8c7 Claudio Fontana
3345 e952d8c7 Claudio Fontana
        if (else_inv && else_inc) {
3346 e952d8c7 Claudio Fontana
            tcg_gen_neg_i64(tcg_rd, tcg_src);
3347 e952d8c7 Claudio Fontana
        } else if (else_inv) {
3348 e952d8c7 Claudio Fontana
            tcg_gen_not_i64(tcg_rd, tcg_src);
3349 e952d8c7 Claudio Fontana
        } else if (else_inc) {
3350 e952d8c7 Claudio Fontana
            tcg_gen_addi_i64(tcg_rd, tcg_src, 1);
3351 e952d8c7 Claudio Fontana
        } else {
3352 e952d8c7 Claudio Fontana
            tcg_gen_mov_i64(tcg_rd, tcg_src);
3353 e952d8c7 Claudio Fontana
        }
3354 e952d8c7 Claudio Fontana
        if (!sf) {
3355 e952d8c7 Claudio Fontana
            tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3356 e952d8c7 Claudio Fontana
        }
3357 e952d8c7 Claudio Fontana
        tcg_gen_br(label_continue);
3358 e952d8c7 Claudio Fontana
        /* match: */
3359 e952d8c7 Claudio Fontana
        gen_set_label(label_match);
3360 e952d8c7 Claudio Fontana
        tcg_src = read_cpu_reg(s, rn, sf);
3361 e952d8c7 Claudio Fontana
        tcg_gen_mov_i64(tcg_rd, tcg_src);
3362 e952d8c7 Claudio Fontana
        /* continue: */
3363 e952d8c7 Claudio Fontana
        gen_set_label(label_continue);
3364 e952d8c7 Claudio Fontana
    }
3365 ad7ee8a2 Claudio Fontana
}
3366 ad7ee8a2 Claudio Fontana
3367 680ead21 Claudio Fontana
static void handle_clz(DisasContext *s, unsigned int sf,
3368 680ead21 Claudio Fontana
                       unsigned int rn, unsigned int rd)
3369 680ead21 Claudio Fontana
{
3370 680ead21 Claudio Fontana
    TCGv_i64 tcg_rd, tcg_rn;
3371 680ead21 Claudio Fontana
    tcg_rd = cpu_reg(s, rd);
3372 680ead21 Claudio Fontana
    tcg_rn = cpu_reg(s, rn);
3373 680ead21 Claudio Fontana
3374 680ead21 Claudio Fontana
    if (sf) {
3375 680ead21 Claudio Fontana
        gen_helper_clz64(tcg_rd, tcg_rn);
3376 680ead21 Claudio Fontana
    } else {
3377 680ead21 Claudio Fontana
        TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
3378 680ead21 Claudio Fontana
        tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
3379 680ead21 Claudio Fontana
        gen_helper_clz(tcg_tmp32, tcg_tmp32);
3380 680ead21 Claudio Fontana
        tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
3381 680ead21 Claudio Fontana
        tcg_temp_free_i32(tcg_tmp32);
3382 680ead21 Claudio Fontana
    }
3383 680ead21 Claudio Fontana
}
3384 680ead21 Claudio Fontana
3385 e80c5020 Claudio Fontana
static void handle_cls(DisasContext *s, unsigned int sf,
3386 e80c5020 Claudio Fontana
                       unsigned int rn, unsigned int rd)
3387 e80c5020 Claudio Fontana
{
3388 e80c5020 Claudio Fontana
    TCGv_i64 tcg_rd, tcg_rn;
3389 e80c5020 Claudio Fontana
    tcg_rd = cpu_reg(s, rd);
3390 e80c5020 Claudio Fontana
    tcg_rn = cpu_reg(s, rn);
3391 e80c5020 Claudio Fontana
3392 e80c5020 Claudio Fontana
    if (sf) {
3393 e80c5020 Claudio Fontana
        gen_helper_cls64(tcg_rd, tcg_rn);
3394 e80c5020 Claudio Fontana
    } else {
3395 e80c5020 Claudio Fontana
        TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
3396 e80c5020 Claudio Fontana
        tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
3397 e80c5020 Claudio Fontana
        gen_helper_cls32(tcg_tmp32, tcg_tmp32);
3398 e80c5020 Claudio Fontana
        tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
3399 e80c5020 Claudio Fontana
        tcg_temp_free_i32(tcg_tmp32);
3400 e80c5020 Claudio Fontana
    }
3401 e80c5020 Claudio Fontana
}
3402 e80c5020 Claudio Fontana
3403 82e14b02 Alexander Graf
static void handle_rbit(DisasContext *s, unsigned int sf,
3404 82e14b02 Alexander Graf
                        unsigned int rn, unsigned int rd)
3405 82e14b02 Alexander Graf
{
3406 82e14b02 Alexander Graf
    TCGv_i64 tcg_rd, tcg_rn;
3407 82e14b02 Alexander Graf
    tcg_rd = cpu_reg(s, rd);
3408 82e14b02 Alexander Graf
    tcg_rn = cpu_reg(s, rn);
3409 82e14b02 Alexander Graf
3410 82e14b02 Alexander Graf
    if (sf) {
3411 82e14b02 Alexander Graf
        gen_helper_rbit64(tcg_rd, tcg_rn);
3412 82e14b02 Alexander Graf
    } else {
3413 82e14b02 Alexander Graf
        TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
3414 82e14b02 Alexander Graf
        tcg_gen_trunc_i64_i32(tcg_tmp32, tcg_rn);
3415 82e14b02 Alexander Graf
        gen_helper_rbit(tcg_tmp32, tcg_tmp32);
3416 82e14b02 Alexander Graf
        tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
3417 82e14b02 Alexander Graf
        tcg_temp_free_i32(tcg_tmp32);
3418 82e14b02 Alexander Graf
    }
3419 82e14b02 Alexander Graf
}
3420 82e14b02 Alexander Graf
3421 45323209 Claudio Fontana
/* C5.6.149 REV with sf==1, opcode==3 ("REV64") */
3422 45323209 Claudio Fontana
static void handle_rev64(DisasContext *s, unsigned int sf,
3423 45323209 Claudio Fontana
                         unsigned int rn, unsigned int rd)
3424 45323209 Claudio Fontana
{
3425 45323209 Claudio Fontana
    if (!sf) {
3426 45323209 Claudio Fontana
        unallocated_encoding(s);
3427 45323209 Claudio Fontana
        return;
3428 45323209 Claudio Fontana
    }
3429 45323209 Claudio Fontana
    tcg_gen_bswap64_i64(cpu_reg(s, rd), cpu_reg(s, rn));
3430 45323209 Claudio Fontana
}
3431 45323209 Claudio Fontana
3432 45323209 Claudio Fontana
/* C5.6.149 REV with sf==0, opcode==2
3433 45323209 Claudio Fontana
 * C5.6.151 REV32 (sf==1, opcode==2)
3434 45323209 Claudio Fontana
 */
3435 45323209 Claudio Fontana
static void handle_rev32(DisasContext *s, unsigned int sf,
3436 45323209 Claudio Fontana
                         unsigned int rn, unsigned int rd)
3437 45323209 Claudio Fontana
{
3438 45323209 Claudio Fontana
    TCGv_i64 tcg_rd = cpu_reg(s, rd);
3439 45323209 Claudio Fontana
3440 45323209 Claudio Fontana
    if (sf) {
3441 45323209 Claudio Fontana
        TCGv_i64 tcg_tmp = tcg_temp_new_i64();
3442 45323209 Claudio Fontana
        TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
3443 45323209 Claudio Fontana
3444 45323209 Claudio Fontana
        /* bswap32_i64 requires zero high word */
3445 45323209 Claudio Fontana
        tcg_gen_ext32u_i64(tcg_tmp, tcg_rn);
3446 45323209 Claudio Fontana
        tcg_gen_bswap32_i64(tcg_rd, tcg_tmp);
3447 45323209 Claudio Fontana
        tcg_gen_shri_i64(tcg_tmp, tcg_rn, 32);
3448 45323209 Claudio Fontana
        tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp);
3449 45323209 Claudio Fontana
        tcg_gen_concat32_i64(tcg_rd, tcg_rd, tcg_tmp);
3450 45323209 Claudio Fontana
3451 45323209 Claudio Fontana
        tcg_temp_free_i64(tcg_tmp);
3452 45323209 Claudio Fontana
    } else {
3453 45323209 Claudio Fontana
        tcg_gen_ext32u_i64(tcg_rd, cpu_reg(s, rn));
3454 45323209 Claudio Fontana
        tcg_gen_bswap32_i64(tcg_rd, tcg_rd);
3455 45323209 Claudio Fontana
    }
3456 45323209 Claudio Fontana
}
3457 45323209 Claudio Fontana
3458 45323209 Claudio Fontana
/* C5.6.150 REV16 (opcode==1) */
3459 45323209 Claudio Fontana
static void handle_rev16(DisasContext *s, unsigned int sf,
3460 45323209 Claudio Fontana
                         unsigned int rn, unsigned int rd)
3461 45323209 Claudio Fontana
{
3462 45323209 Claudio Fontana
    TCGv_i64 tcg_rd = cpu_reg(s, rd);
3463 45323209 Claudio Fontana
    TCGv_i64 tcg_tmp = tcg_temp_new_i64();
3464 45323209 Claudio Fontana
    TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
3465 45323209 Claudio Fontana
3466 45323209 Claudio Fontana
    tcg_gen_andi_i64(tcg_tmp, tcg_rn, 0xffff);
3467 45323209 Claudio Fontana
    tcg_gen_bswap16_i64(tcg_rd, tcg_tmp);
3468 45323209 Claudio Fontana
3469 45323209 Claudio Fontana
    tcg_gen_shri_i64(tcg_tmp, tcg_rn, 16);
3470 45323209 Claudio Fontana
    tcg_gen_andi_i64(tcg_tmp, tcg_tmp, 0xffff);
3471 45323209 Claudio Fontana
    tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
3472 45323209 Claudio Fontana
    tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, 16, 16);
3473 45323209 Claudio Fontana
3474 45323209 Claudio Fontana
    if (sf) {
3475 45323209 Claudio Fontana
        tcg_gen_shri_i64(tcg_tmp, tcg_rn, 32);
3476 45323209 Claudio Fontana
        tcg_gen_andi_i64(tcg_tmp, tcg_tmp, 0xffff);
3477 45323209 Claudio Fontana
        tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
3478 45323209 Claudio Fontana
        tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, 32, 16);
3479 45323209 Claudio Fontana
3480 45323209 Claudio Fontana
        tcg_gen_shri_i64(tcg_tmp, tcg_rn, 48);
3481 45323209 Claudio Fontana
        tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
3482 45323209 Claudio Fontana
        tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, 48, 16);
3483 45323209 Claudio Fontana
    }
3484 45323209 Claudio Fontana
3485 45323209 Claudio Fontana
    tcg_temp_free_i64(tcg_tmp);
3486 45323209 Claudio Fontana
}
3487 45323209 Claudio Fontana
3488 680ead21 Claudio Fontana
/* C3.5.7 Data-processing (1 source)
3489 680ead21 Claudio Fontana
 *   31  30  29  28             21 20     16 15    10 9    5 4    0
3490 680ead21 Claudio Fontana
 * +----+---+---+-----------------+---------+--------+------+------+
3491 680ead21 Claudio Fontana
 * | sf | 1 | S | 1 1 0 1 0 1 1 0 | opcode2 | opcode |  Rn  |  Rd  |
3492 680ead21 Claudio Fontana
 * +----+---+---+-----------------+---------+--------+------+------+
3493 680ead21 Claudio Fontana
 */
3494 ad7ee8a2 Claudio Fontana
static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
3495 ad7ee8a2 Claudio Fontana
{
3496 680ead21 Claudio Fontana
    unsigned int sf, opcode, rn, rd;
3497 680ead21 Claudio Fontana
3498 680ead21 Claudio Fontana
    if (extract32(insn, 29, 1) || extract32(insn, 16, 5)) {
3499 680ead21 Claudio Fontana
        unallocated_encoding(s);
3500 680ead21 Claudio Fontana
        return;
3501 680ead21 Claudio Fontana
    }
3502 680ead21 Claudio Fontana
3503 680ead21 Claudio Fontana
    sf = extract32(insn, 31, 1);
3504 680ead21 Claudio Fontana
    opcode = extract32(insn, 10, 6);
3505 680ead21 Claudio Fontana
    rn = extract32(insn, 5, 5);
3506 680ead21 Claudio Fontana
    rd = extract32(insn, 0, 5);
3507 680ead21 Claudio Fontana
3508 680ead21 Claudio Fontana
    switch (opcode) {
3509 680ead21 Claudio Fontana
    case 0: /* RBIT */
3510 82e14b02 Alexander Graf
        handle_rbit(s, sf, rn, rd);
3511 82e14b02 Alexander Graf
        break;
3512 680ead21 Claudio Fontana
    case 1: /* REV16 */
3513 45323209 Claudio Fontana
        handle_rev16(s, sf, rn, rd);
3514 45323209 Claudio Fontana
        break;
3515 680ead21 Claudio Fontana
    case 2: /* REV32 */
3516 45323209 Claudio Fontana
        handle_rev32(s, sf, rn, rd);
3517 45323209 Claudio Fontana
        break;
3518 680ead21 Claudio Fontana
    case 3: /* REV64 */
3519 45323209 Claudio Fontana
        handle_rev64(s, sf, rn, rd);
3520 680ead21 Claudio Fontana
        break;
3521 680ead21 Claudio Fontana
    case 4: /* CLZ */
3522 680ead21 Claudio Fontana
        handle_clz(s, sf, rn, rd);
3523 680ead21 Claudio Fontana
        break;
3524 680ead21 Claudio Fontana
    case 5: /* CLS */
3525 e80c5020 Claudio Fontana
        handle_cls(s, sf, rn, rd);
3526 680ead21 Claudio Fontana
        break;
3527 680ead21 Claudio Fontana
    }
3528 ad7ee8a2 Claudio Fontana
}
3529 ad7ee8a2 Claudio Fontana
3530 8220e911 Alexander Graf
static void handle_div(DisasContext *s, bool is_signed, unsigned int sf,
3531 8220e911 Alexander Graf
                       unsigned int rm, unsigned int rn, unsigned int rd)
3532 8220e911 Alexander Graf
{
3533 8220e911 Alexander Graf
    TCGv_i64 tcg_n, tcg_m, tcg_rd;
3534 8220e911 Alexander Graf
    tcg_rd = cpu_reg(s, rd);
3535 8220e911 Alexander Graf
3536 8220e911 Alexander Graf
    if (!sf && is_signed) {
3537 8220e911 Alexander Graf
        tcg_n = new_tmp_a64(s);
3538 8220e911 Alexander Graf
        tcg_m = new_tmp_a64(s);
3539 8220e911 Alexander Graf
        tcg_gen_ext32s_i64(tcg_n, cpu_reg(s, rn));
3540 8220e911 Alexander Graf
        tcg_gen_ext32s_i64(tcg_m, cpu_reg(s, rm));
3541 8220e911 Alexander Graf
    } else {
3542 8220e911 Alexander Graf
        tcg_n = read_cpu_reg(s, rn, sf);
3543 8220e911 Alexander Graf
        tcg_m = read_cpu_reg(s, rm, sf);
3544 8220e911 Alexander Graf
    }
3545 8220e911 Alexander Graf
3546 8220e911 Alexander Graf
    if (is_signed) {
3547 8220e911 Alexander Graf
        gen_helper_sdiv64(tcg_rd, tcg_n, tcg_m);
3548 8220e911 Alexander Graf
    } else {
3549 8220e911 Alexander Graf
        gen_helper_udiv64(tcg_rd, tcg_n, tcg_m);
3550 8220e911 Alexander Graf
    }
3551 8220e911 Alexander Graf
3552 8220e911 Alexander Graf
    if (!sf) { /* zero extend final result */
3553 8220e911 Alexander Graf
        tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3554 8220e911 Alexander Graf
    }
3555 8220e911 Alexander Graf
}
3556 8220e911 Alexander Graf
3557 6c1adc91 Alexander Graf
/* C5.6.115 LSLV, C5.6.118 LSRV, C5.6.17 ASRV, C5.6.154 RORV */
3558 6c1adc91 Alexander Graf
static void handle_shift_reg(DisasContext *s,
3559 6c1adc91 Alexander Graf
                             enum a64_shift_type shift_type, unsigned int sf,
3560 6c1adc91 Alexander Graf
                             unsigned int rm, unsigned int rn, unsigned int rd)
3561 6c1adc91 Alexander Graf
{
3562 6c1adc91 Alexander Graf
    TCGv_i64 tcg_shift = tcg_temp_new_i64();
3563 6c1adc91 Alexander Graf
    TCGv_i64 tcg_rd = cpu_reg(s, rd);
3564 6c1adc91 Alexander Graf
    TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
3565 6c1adc91 Alexander Graf
3566 6c1adc91 Alexander Graf
    tcg_gen_andi_i64(tcg_shift, cpu_reg(s, rm), sf ? 63 : 31);
3567 6c1adc91 Alexander Graf
    shift_reg(tcg_rd, tcg_rn, sf, shift_type, tcg_shift);
3568 6c1adc91 Alexander Graf
    tcg_temp_free_i64(tcg_shift);
3569 6c1adc91 Alexander Graf
}
3570 6c1adc91 Alexander Graf
3571 8220e911 Alexander Graf
/* C3.5.8 Data-processing (2 source)
3572 8220e911 Alexander Graf
 *   31   30  29 28             21 20  16 15    10 9    5 4    0
3573 8220e911 Alexander Graf
 * +----+---+---+-----------------+------+--------+------+------+
3574 8220e911 Alexander Graf
 * | sf | 0 | S | 1 1 0 1 0 1 1 0 |  Rm  | opcode |  Rn  |  Rd  |
3575 8220e911 Alexander Graf
 * +----+---+---+-----------------+------+--------+------+------+
3576 8220e911 Alexander Graf
 */
3577 ad7ee8a2 Claudio Fontana
static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
3578 ad7ee8a2 Claudio Fontana
{
3579 8220e911 Alexander Graf
    unsigned int sf, rm, opcode, rn, rd;
3580 8220e911 Alexander Graf
    sf = extract32(insn, 31, 1);
3581 8220e911 Alexander Graf
    rm = extract32(insn, 16, 5);
3582 8220e911 Alexander Graf
    opcode = extract32(insn, 10, 6);
3583 8220e911 Alexander Graf
    rn = extract32(insn, 5, 5);
3584 8220e911 Alexander Graf
    rd = extract32(insn, 0, 5);
3585 8220e911 Alexander Graf
3586 8220e911 Alexander Graf
    if (extract32(insn, 29, 1)) {
3587 8220e911 Alexander Graf
        unallocated_encoding(s);
3588 8220e911 Alexander Graf
        return;
3589 8220e911 Alexander Graf
    }
3590 8220e911 Alexander Graf
3591 8220e911 Alexander Graf
    switch (opcode) {
3592 8220e911 Alexander Graf
    case 2: /* UDIV */
3593 8220e911 Alexander Graf
        handle_div(s, false, sf, rm, rn, rd);
3594 8220e911 Alexander Graf
        break;
3595 8220e911 Alexander Graf
    case 3: /* SDIV */
3596 8220e911 Alexander Graf
        handle_div(s, true, sf, rm, rn, rd);
3597 8220e911 Alexander Graf
        break;
3598 8220e911 Alexander Graf
    case 8: /* LSLV */
3599 6c1adc91 Alexander Graf
        handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd);
3600 6c1adc91 Alexander Graf
        break;
3601 8220e911 Alexander Graf
    case 9: /* LSRV */
3602 6c1adc91 Alexander Graf
        handle_shift_reg(s, A64_SHIFT_TYPE_LSR, sf, rm, rn, rd);
3603 6c1adc91 Alexander Graf
        break;
3604 8220e911 Alexander Graf
    case 10: /* ASRV */
3605 6c1adc91 Alexander Graf
        handle_shift_reg(s, A64_SHIFT_TYPE_ASR, sf, rm, rn, rd);
3606 6c1adc91 Alexander Graf
        break;
3607 8220e911 Alexander Graf
    case 11: /* RORV */
3608 6c1adc91 Alexander Graf
        handle_shift_reg(s, A64_SHIFT_TYPE_ROR, sf, rm, rn, rd);
3609 6c1adc91 Alexander Graf
        break;
3610 8220e911 Alexander Graf
    case 16:
3611 8220e911 Alexander Graf
    case 17:
3612 8220e911 Alexander Graf
    case 18:
3613 8220e911 Alexander Graf
    case 19:
3614 8220e911 Alexander Graf
    case 20:
3615 8220e911 Alexander Graf
    case 21:
3616 8220e911 Alexander Graf
    case 22:
3617 8220e911 Alexander Graf
    case 23: /* CRC32 */
3618 8220e911 Alexander Graf
        unsupported_encoding(s, insn);
3619 8220e911 Alexander Graf
        break;
3620 8220e911 Alexander Graf
    default:
3621 8220e911 Alexander Graf
        unallocated_encoding(s);
3622 8220e911 Alexander Graf
        break;
3623 8220e911 Alexander Graf
    }
3624 ad7ee8a2 Claudio Fontana
}
3625 ad7ee8a2 Claudio Fontana
3626 ad7ee8a2 Claudio Fontana
/* C3.5 Data processing - register */
3627 ad7ee8a2 Claudio Fontana
static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
3628 ad7ee8a2 Claudio Fontana
{
3629 ad7ee8a2 Claudio Fontana
    switch (extract32(insn, 24, 5)) {
3630 ad7ee8a2 Claudio Fontana
    case 0x0a: /* Logical (shifted register) */
3631 ad7ee8a2 Claudio Fontana
        disas_logic_reg(s, insn);
3632 ad7ee8a2 Claudio Fontana
        break;
3633 ad7ee8a2 Claudio Fontana
    case 0x0b: /* Add/subtract */
3634 ad7ee8a2 Claudio Fontana
        if (insn & (1 << 21)) { /* (extended register) */
3635 ad7ee8a2 Claudio Fontana
            disas_add_sub_ext_reg(s, insn);
3636 ad7ee8a2 Claudio Fontana
        } else {
3637 ad7ee8a2 Claudio Fontana
            disas_add_sub_reg(s, insn);
3638 ad7ee8a2 Claudio Fontana
        }
3639 ad7ee8a2 Claudio Fontana
        break;
3640 ad7ee8a2 Claudio Fontana
    case 0x1b: /* Data-processing (3 source) */
3641 ad7ee8a2 Claudio Fontana
        disas_data_proc_3src(s, insn);
3642 ad7ee8a2 Claudio Fontana
        break;
3643 ad7ee8a2 Claudio Fontana
    case 0x1a:
3644 ad7ee8a2 Claudio Fontana
        switch (extract32(insn, 21, 3)) {
3645 ad7ee8a2 Claudio Fontana
        case 0x0: /* Add/subtract (with carry) */
3646 ad7ee8a2 Claudio Fontana
            disas_adc_sbc(s, insn);
3647 ad7ee8a2 Claudio Fontana
            break;
3648 ad7ee8a2 Claudio Fontana
        case 0x2: /* Conditional compare */
3649 750813cf Claudio Fontana
            disas_cc(s, insn); /* both imm and reg forms */
3650 ad7ee8a2 Claudio Fontana
            break;
3651 ad7ee8a2 Claudio Fontana
        case 0x4: /* Conditional select */
3652 ad7ee8a2 Claudio Fontana
            disas_cond_select(s, insn);
3653 ad7ee8a2 Claudio Fontana
            break;
3654 ad7ee8a2 Claudio Fontana
        case 0x6: /* Data-processing */
3655 ad7ee8a2 Claudio Fontana
            if (insn & (1 << 30)) { /* (1 source) */
3656 ad7ee8a2 Claudio Fontana
                disas_data_proc_1src(s, insn);
3657 ad7ee8a2 Claudio Fontana
            } else {            /* (2 source) */
3658 ad7ee8a2 Claudio Fontana
                disas_data_proc_2src(s, insn);
3659 ad7ee8a2 Claudio Fontana
            }
3660 ad7ee8a2 Claudio Fontana
            break;
3661 ad7ee8a2 Claudio Fontana
        default:
3662 ad7ee8a2 Claudio Fontana
            unallocated_encoding(s);
3663 ad7ee8a2 Claudio Fontana
            break;
3664 ad7ee8a2 Claudio Fontana
        }
3665 ad7ee8a2 Claudio Fontana
        break;
3666 ad7ee8a2 Claudio Fontana
    default:
3667 ad7ee8a2 Claudio Fontana
        unallocated_encoding(s);
3668 ad7ee8a2 Claudio Fontana
        break;
3669 ad7ee8a2 Claudio Fontana
    }
3670 ad7ee8a2 Claudio Fontana
}
3671 ad7ee8a2 Claudio Fontana
3672 da7dafe7 Claudio Fontana
static void handle_fp_compare(DisasContext *s, bool is_double,
3673 da7dafe7 Claudio Fontana
                              unsigned int rn, unsigned int rm,
3674 da7dafe7 Claudio Fontana
                              bool cmp_with_zero, bool signal_all_nans)
3675 da7dafe7 Claudio Fontana
{
3676 da7dafe7 Claudio Fontana
    TCGv_i64 tcg_flags = tcg_temp_new_i64();
3677 da7dafe7 Claudio Fontana
    TCGv_ptr fpst = get_fpstatus_ptr();
3678 da7dafe7 Claudio Fontana
3679 da7dafe7 Claudio Fontana
    if (is_double) {
3680 da7dafe7 Claudio Fontana
        TCGv_i64 tcg_vn, tcg_vm;
3681 da7dafe7 Claudio Fontana
3682 da7dafe7 Claudio Fontana
        tcg_vn = read_fp_dreg(s, rn);
3683 da7dafe7 Claudio Fontana
        if (cmp_with_zero) {
3684 da7dafe7 Claudio Fontana
            tcg_vm = tcg_const_i64(0);
3685 da7dafe7 Claudio Fontana
        } else {
3686 da7dafe7 Claudio Fontana
            tcg_vm = read_fp_dreg(s, rm);
3687 da7dafe7 Claudio Fontana
        }
3688 da7dafe7 Claudio Fontana
        if (signal_all_nans) {
3689 da7dafe7 Claudio Fontana
            gen_helper_vfp_cmped_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
3690 da7dafe7 Claudio Fontana
        } else {
3691 da7dafe7 Claudio Fontana
            gen_helper_vfp_cmpd_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
3692 da7dafe7 Claudio Fontana
        }
3693 da7dafe7 Claudio Fontana
        tcg_temp_free_i64(tcg_vn);
3694 da7dafe7 Claudio Fontana
        tcg_temp_free_i64(tcg_vm);
3695 da7dafe7 Claudio Fontana
    } else {
3696 da7dafe7 Claudio Fontana
        TCGv_i32 tcg_vn, tcg_vm;
3697 da7dafe7 Claudio Fontana
3698 da7dafe7 Claudio Fontana
        tcg_vn = read_fp_sreg(s, rn);
3699 da7dafe7 Claudio Fontana
        if (cmp_with_zero) {
3700 da7dafe7 Claudio Fontana
            tcg_vm = tcg_const_i32(0);
3701 da7dafe7 Claudio Fontana
        } else {
3702 da7dafe7 Claudio Fontana
            tcg_vm = read_fp_sreg(s, rm);
3703 da7dafe7 Claudio Fontana
        }
3704 da7dafe7 Claudio Fontana
        if (signal_all_nans) {
3705 da7dafe7 Claudio Fontana
            gen_helper_vfp_cmpes_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
3706 da7dafe7 Claudio Fontana
        } else {
3707 da7dafe7 Claudio Fontana
            gen_helper_vfp_cmps_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
3708 da7dafe7 Claudio Fontana
        }
3709 da7dafe7 Claudio Fontana
        tcg_temp_free_i32(tcg_vn);
3710 da7dafe7 Claudio Fontana
        tcg_temp_free_i32(tcg_vm);
3711 da7dafe7 Claudio Fontana
    }
3712 da7dafe7 Claudio Fontana
3713 da7dafe7 Claudio Fontana
    tcg_temp_free_ptr(fpst);
3714 da7dafe7 Claudio Fontana
3715 da7dafe7 Claudio Fontana
    gen_set_nzcv(tcg_flags);
3716 da7dafe7 Claudio Fontana
3717 da7dafe7 Claudio Fontana
    tcg_temp_free_i64(tcg_flags);
3718 da7dafe7 Claudio Fontana
}
3719 da7dafe7 Claudio Fontana
3720 faa0ba46 Peter Maydell
/* C3.6.22 Floating point compare
3721 faa0ba46 Peter Maydell
 *   31  30  29 28       24 23  22  21 20  16 15 14 13  10    9    5 4     0
3722 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+------+-----+---------+------+-------+
3723 faa0ba46 Peter Maydell
 * | M | 0 | S | 1 1 1 1 0 | type | 1 |  Rm  | op  | 1 0 0 0 |  Rn  |  op2  |
3724 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+------+-----+---------+------+-------+
3725 faa0ba46 Peter Maydell
 */
3726 faa0ba46 Peter Maydell
static void disas_fp_compare(DisasContext *s, uint32_t insn)
3727 faa0ba46 Peter Maydell
{
3728 da7dafe7 Claudio Fontana
    unsigned int mos, type, rm, op, rn, opc, op2r;
3729 da7dafe7 Claudio Fontana
3730 da7dafe7 Claudio Fontana
    mos = extract32(insn, 29, 3);
3731 da7dafe7 Claudio Fontana
    type = extract32(insn, 22, 2); /* 0 = single, 1 = double */
3732 da7dafe7 Claudio Fontana
    rm = extract32(insn, 16, 5);
3733 da7dafe7 Claudio Fontana
    op = extract32(insn, 14, 2);
3734 da7dafe7 Claudio Fontana
    rn = extract32(insn, 5, 5);
3735 da7dafe7 Claudio Fontana
    opc = extract32(insn, 3, 2);
3736 da7dafe7 Claudio Fontana
    op2r = extract32(insn, 0, 3);
3737 da7dafe7 Claudio Fontana
3738 da7dafe7 Claudio Fontana
    if (mos || op || op2r || type > 1) {
3739 da7dafe7 Claudio Fontana
        unallocated_encoding(s);
3740 da7dafe7 Claudio Fontana
        return;
3741 da7dafe7 Claudio Fontana
    }
3742 da7dafe7 Claudio Fontana
3743 da7dafe7 Claudio Fontana
    handle_fp_compare(s, type, rn, rm, opc & 1, opc & 2);
3744 faa0ba46 Peter Maydell
}
3745 faa0ba46 Peter Maydell
3746 faa0ba46 Peter Maydell
/* C3.6.23 Floating point conditional compare
3747 faa0ba46 Peter Maydell
 *   31  30  29 28       24 23  22  21 20  16 15  12 11 10 9    5  4   3    0
3748 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+------+------+-----+------+----+------+
3749 faa0ba46 Peter Maydell
 * | M | 0 | S | 1 1 1 1 0 | type | 1 |  Rm  | cond | 0 1 |  Rn  | op | nzcv |
3750 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+------+------+-----+------+----+------+
3751 faa0ba46 Peter Maydell
 */
3752 faa0ba46 Peter Maydell
static void disas_fp_ccomp(DisasContext *s, uint32_t insn)
3753 faa0ba46 Peter Maydell
{
3754 513f1d76 Claudio Fontana
    unsigned int mos, type, rm, cond, rn, op, nzcv;
3755 513f1d76 Claudio Fontana
    TCGv_i64 tcg_flags;
3756 513f1d76 Claudio Fontana
    int label_continue = -1;
3757 513f1d76 Claudio Fontana
3758 513f1d76 Claudio Fontana
    mos = extract32(insn, 29, 3);
3759 513f1d76 Claudio Fontana
    type = extract32(insn, 22, 2); /* 0 = single, 1 = double */
3760 513f1d76 Claudio Fontana
    rm = extract32(insn, 16, 5);
3761 513f1d76 Claudio Fontana
    cond = extract32(insn, 12, 4);
3762 513f1d76 Claudio Fontana
    rn = extract32(insn, 5, 5);
3763 513f1d76 Claudio Fontana
    op = extract32(insn, 4, 1);
3764 513f1d76 Claudio Fontana
    nzcv = extract32(insn, 0, 4);
3765 513f1d76 Claudio Fontana
3766 513f1d76 Claudio Fontana
    if (mos || type > 1) {
3767 513f1d76 Claudio Fontana
        unallocated_encoding(s);
3768 513f1d76 Claudio Fontana
        return;
3769 513f1d76 Claudio Fontana
    }
3770 513f1d76 Claudio Fontana
3771 513f1d76 Claudio Fontana
    if (cond < 0x0e) { /* not always */
3772 513f1d76 Claudio Fontana
        int label_match = gen_new_label();
3773 513f1d76 Claudio Fontana
        label_continue = gen_new_label();
3774 513f1d76 Claudio Fontana
        arm_gen_test_cc(cond, label_match);
3775 513f1d76 Claudio Fontana
        /* nomatch: */
3776 513f1d76 Claudio Fontana
        tcg_flags = tcg_const_i64(nzcv << 28);
3777 513f1d76 Claudio Fontana
        gen_set_nzcv(tcg_flags);
3778 513f1d76 Claudio Fontana
        tcg_temp_free_i64(tcg_flags);
3779 513f1d76 Claudio Fontana
        tcg_gen_br(label_continue);
3780 513f1d76 Claudio Fontana
        gen_set_label(label_match);
3781 513f1d76 Claudio Fontana
    }
3782 513f1d76 Claudio Fontana
3783 513f1d76 Claudio Fontana
    handle_fp_compare(s, type, rn, rm, false, op);
3784 513f1d76 Claudio Fontana
3785 513f1d76 Claudio Fontana
    if (cond < 0x0e) {
3786 513f1d76 Claudio Fontana
        gen_set_label(label_continue);
3787 513f1d76 Claudio Fontana
    }
3788 faa0ba46 Peter Maydell
}
3789 faa0ba46 Peter Maydell
3790 5640ff62 Claudio Fontana
/* copy src FP register to dst FP register; type specifies single or double */
3791 5640ff62 Claudio Fontana
static void gen_mov_fp2fp(DisasContext *s, int type, int dst, int src)
3792 5640ff62 Claudio Fontana
{
3793 5640ff62 Claudio Fontana
    if (type) {
3794 5640ff62 Claudio Fontana
        TCGv_i64 v = read_fp_dreg(s, src);
3795 5640ff62 Claudio Fontana
        write_fp_dreg(s, dst, v);
3796 5640ff62 Claudio Fontana
        tcg_temp_free_i64(v);
3797 5640ff62 Claudio Fontana
    } else {
3798 5640ff62 Claudio Fontana
        TCGv_i32 v = read_fp_sreg(s, src);
3799 5640ff62 Claudio Fontana
        write_fp_sreg(s, dst, v);
3800 5640ff62 Claudio Fontana
        tcg_temp_free_i32(v);
3801 5640ff62 Claudio Fontana
    }
3802 5640ff62 Claudio Fontana
}
3803 5640ff62 Claudio Fontana
3804 faa0ba46 Peter Maydell
/* C3.6.24 Floating point conditional select
3805 faa0ba46 Peter Maydell
 *   31  30  29 28       24 23  22  21 20  16 15  12 11 10 9    5 4    0
3806 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+------+------+-----+------+------+
3807 faa0ba46 Peter Maydell
 * | M | 0 | S | 1 1 1 1 0 | type | 1 |  Rm  | cond | 1 1 |  Rn  |  Rd  |
3808 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+------+------+-----+------+------+
3809 faa0ba46 Peter Maydell
 */
3810 faa0ba46 Peter Maydell
static void disas_fp_csel(DisasContext *s, uint32_t insn)
3811 faa0ba46 Peter Maydell
{
3812 5640ff62 Claudio Fontana
    unsigned int mos, type, rm, cond, rn, rd;
3813 5640ff62 Claudio Fontana
    int label_continue = -1;
3814 5640ff62 Claudio Fontana
3815 5640ff62 Claudio Fontana
    mos = extract32(insn, 29, 3);
3816 5640ff62 Claudio Fontana
    type = extract32(insn, 22, 2); /* 0 = single, 1 = double */
3817 5640ff62 Claudio Fontana
    rm = extract32(insn, 16, 5);
3818 5640ff62 Claudio Fontana
    cond = extract32(insn, 12, 4);
3819 5640ff62 Claudio Fontana
    rn = extract32(insn, 5, 5);
3820 5640ff62 Claudio Fontana
    rd = extract32(insn, 0, 5);
3821 5640ff62 Claudio Fontana
3822 5640ff62 Claudio Fontana
    if (mos || type > 1) {
3823 5640ff62 Claudio Fontana
        unallocated_encoding(s);
3824 5640ff62 Claudio Fontana
        return;
3825 5640ff62 Claudio Fontana
    }
3826 5640ff62 Claudio Fontana
3827 5640ff62 Claudio Fontana
    if (cond < 0x0e) { /* not always */
3828 5640ff62 Claudio Fontana
        int label_match = gen_new_label();
3829 5640ff62 Claudio Fontana
        label_continue = gen_new_label();
3830 5640ff62 Claudio Fontana
        arm_gen_test_cc(cond, label_match);
3831 5640ff62 Claudio Fontana
        /* nomatch: */
3832 5640ff62 Claudio Fontana
        gen_mov_fp2fp(s, type, rd, rm);
3833 5640ff62 Claudio Fontana
        tcg_gen_br(label_continue);
3834 5640ff62 Claudio Fontana
        gen_set_label(label_match);
3835 5640ff62 Claudio Fontana
    }
3836 5640ff62 Claudio Fontana
3837 5640ff62 Claudio Fontana
    gen_mov_fp2fp(s, type, rd, rn);
3838 5640ff62 Claudio Fontana
3839 5640ff62 Claudio Fontana
    if (cond < 0x0e) { /* continue */
3840 5640ff62 Claudio Fontana
        gen_set_label(label_continue);
3841 5640ff62 Claudio Fontana
    }
3842 faa0ba46 Peter Maydell
}
3843 faa0ba46 Peter Maydell
3844 d9b0848d Peter Maydell
/* C3.6.25 Floating-point data-processing (1 source) - single precision */
3845 d9b0848d Peter Maydell
static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
3846 d9b0848d Peter Maydell
{
3847 d9b0848d Peter Maydell
    TCGv_ptr fpst;
3848 d9b0848d Peter Maydell
    TCGv_i32 tcg_op;
3849 d9b0848d Peter Maydell
    TCGv_i32 tcg_res;
3850 d9b0848d Peter Maydell
3851 d9b0848d Peter Maydell
    fpst = get_fpstatus_ptr();
3852 d9b0848d Peter Maydell
    tcg_op = read_fp_sreg(s, rn);
3853 d9b0848d Peter Maydell
    tcg_res = tcg_temp_new_i32();
3854 d9b0848d Peter Maydell
3855 d9b0848d Peter Maydell
    switch (opcode) {
3856 d9b0848d Peter Maydell
    case 0x0: /* FMOV */
3857 d9b0848d Peter Maydell
        tcg_gen_mov_i32(tcg_res, tcg_op);
3858 d9b0848d Peter Maydell
        break;
3859 d9b0848d Peter Maydell
    case 0x1: /* FABS */
3860 d9b0848d Peter Maydell
        gen_helper_vfp_abss(tcg_res, tcg_op);
3861 d9b0848d Peter Maydell
        break;
3862 d9b0848d Peter Maydell
    case 0x2: /* FNEG */
3863 d9b0848d Peter Maydell
        gen_helper_vfp_negs(tcg_res, tcg_op);
3864 d9b0848d Peter Maydell
        break;
3865 d9b0848d Peter Maydell
    case 0x3: /* FSQRT */
3866 d9b0848d Peter Maydell
        gen_helper_vfp_sqrts(tcg_res, tcg_op, cpu_env);
3867 d9b0848d Peter Maydell
        break;
3868 d9b0848d Peter Maydell
    case 0x8: /* FRINTN */
3869 d9b0848d Peter Maydell
    case 0x9: /* FRINTP */
3870 d9b0848d Peter Maydell
    case 0xa: /* FRINTM */
3871 d9b0848d Peter Maydell
    case 0xb: /* FRINTZ */
3872 d9b0848d Peter Maydell
    case 0xc: /* FRINTA */
3873 d9b0848d Peter Maydell
    {
3874 d9b0848d Peter Maydell
        TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
3875 d9b0848d Peter Maydell
3876 d9b0848d Peter Maydell
        gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
3877 d9b0848d Peter Maydell
        gen_helper_rints(tcg_res, tcg_op, fpst);
3878 d9b0848d Peter Maydell
3879 d9b0848d Peter Maydell
        gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
3880 d9b0848d Peter Maydell
        tcg_temp_free_i32(tcg_rmode);
3881 d9b0848d Peter Maydell
        break;
3882 d9b0848d Peter Maydell
    }
3883 d9b0848d Peter Maydell
    case 0xe: /* FRINTX */
3884 d9b0848d Peter Maydell
        gen_helper_rints_exact(tcg_res, tcg_op, fpst);
3885 d9b0848d Peter Maydell
        break;
3886 d9b0848d Peter Maydell
    case 0xf: /* FRINTI */
3887 d9b0848d Peter Maydell
        gen_helper_rints(tcg_res, tcg_op, fpst);
3888 d9b0848d Peter Maydell
        break;
3889 d9b0848d Peter Maydell
    default:
3890 d9b0848d Peter Maydell
        abort();
3891 d9b0848d Peter Maydell
    }
3892 d9b0848d Peter Maydell
3893 d9b0848d Peter Maydell
    write_fp_sreg(s, rd, tcg_res);
3894 d9b0848d Peter Maydell
3895 d9b0848d Peter Maydell
    tcg_temp_free_ptr(fpst);
3896 d9b0848d Peter Maydell
    tcg_temp_free_i32(tcg_op);
3897 d9b0848d Peter Maydell
    tcg_temp_free_i32(tcg_res);
3898 d9b0848d Peter Maydell
}
3899 d9b0848d Peter Maydell
3900 d9b0848d Peter Maydell
/* C3.6.25 Floating-point data-processing (1 source) - double precision */
3901 d9b0848d Peter Maydell
static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
3902 d9b0848d Peter Maydell
{
3903 d9b0848d Peter Maydell
    TCGv_ptr fpst;
3904 d9b0848d Peter Maydell
    TCGv_i64 tcg_op;
3905 d9b0848d Peter Maydell
    TCGv_i64 tcg_res;
3906 d9b0848d Peter Maydell
3907 d9b0848d Peter Maydell
    fpst = get_fpstatus_ptr();
3908 d9b0848d Peter Maydell
    tcg_op = read_fp_dreg(s, rn);
3909 d9b0848d Peter Maydell
    tcg_res = tcg_temp_new_i64();
3910 d9b0848d Peter Maydell
3911 d9b0848d Peter Maydell
    switch (opcode) {
3912 d9b0848d Peter Maydell
    case 0x0: /* FMOV */
3913 d9b0848d Peter Maydell
        tcg_gen_mov_i64(tcg_res, tcg_op);
3914 d9b0848d Peter Maydell
        break;
3915 d9b0848d Peter Maydell
    case 0x1: /* FABS */
3916 d9b0848d Peter Maydell
        gen_helper_vfp_absd(tcg_res, tcg_op);
3917 d9b0848d Peter Maydell
        break;
3918 d9b0848d Peter Maydell
    case 0x2: /* FNEG */
3919 d9b0848d Peter Maydell
        gen_helper_vfp_negd(tcg_res, tcg_op);
3920 d9b0848d Peter Maydell
        break;
3921 d9b0848d Peter Maydell
    case 0x3: /* FSQRT */
3922 d9b0848d Peter Maydell
        gen_helper_vfp_sqrtd(tcg_res, tcg_op, cpu_env);
3923 d9b0848d Peter Maydell
        break;
3924 d9b0848d Peter Maydell
    case 0x8: /* FRINTN */
3925 d9b0848d Peter Maydell
    case 0x9: /* FRINTP */
3926 d9b0848d Peter Maydell
    case 0xa: /* FRINTM */
3927 d9b0848d Peter Maydell
    case 0xb: /* FRINTZ */
3928 d9b0848d Peter Maydell
    case 0xc: /* FRINTA */
3929 d9b0848d Peter Maydell
    {
3930 d9b0848d Peter Maydell
        TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
3931 d9b0848d Peter Maydell
3932 d9b0848d Peter Maydell
        gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
3933 d9b0848d Peter Maydell
        gen_helper_rintd(tcg_res, tcg_op, fpst);
3934 d9b0848d Peter Maydell
3935 d9b0848d Peter Maydell
        gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
3936 d9b0848d Peter Maydell
        tcg_temp_free_i32(tcg_rmode);
3937 d9b0848d Peter Maydell
        break;
3938 d9b0848d Peter Maydell
    }
3939 d9b0848d Peter Maydell
    case 0xe: /* FRINTX */
3940 d9b0848d Peter Maydell
        gen_helper_rintd_exact(tcg_res, tcg_op, fpst);
3941 d9b0848d Peter Maydell
        break;
3942 d9b0848d Peter Maydell
    case 0xf: /* FRINTI */
3943 d9b0848d Peter Maydell
        gen_helper_rintd(tcg_res, tcg_op, fpst);
3944 d9b0848d Peter Maydell
        break;
3945 d9b0848d Peter Maydell
    default:
3946 d9b0848d Peter Maydell
        abort();
3947 d9b0848d Peter Maydell
    }
3948 d9b0848d Peter Maydell
3949 d9b0848d Peter Maydell
    write_fp_dreg(s, rd, tcg_res);
3950 d9b0848d Peter Maydell
3951 d9b0848d Peter Maydell
    tcg_temp_free_ptr(fpst);
3952 d9b0848d Peter Maydell
    tcg_temp_free_i64(tcg_op);
3953 d9b0848d Peter Maydell
    tcg_temp_free_i64(tcg_res);
3954 d9b0848d Peter Maydell
}
3955 d9b0848d Peter Maydell
3956 8900aad2 Peter Maydell
static void handle_fp_fcvt(DisasContext *s, int opcode,
3957 8900aad2 Peter Maydell
                           int rd, int rn, int dtype, int ntype)
3958 8900aad2 Peter Maydell
{
3959 8900aad2 Peter Maydell
    switch (ntype) {
3960 8900aad2 Peter Maydell
    case 0x0:
3961 8900aad2 Peter Maydell
    {
3962 8900aad2 Peter Maydell
        TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
3963 8900aad2 Peter Maydell
        if (dtype == 1) {
3964 8900aad2 Peter Maydell
            /* Single to double */
3965 8900aad2 Peter Maydell
            TCGv_i64 tcg_rd = tcg_temp_new_i64();
3966 8900aad2 Peter Maydell
            gen_helper_vfp_fcvtds(tcg_rd, tcg_rn, cpu_env);
3967 8900aad2 Peter Maydell
            write_fp_dreg(s, rd, tcg_rd);
3968 8900aad2 Peter Maydell
            tcg_temp_free_i64(tcg_rd);
3969 8900aad2 Peter Maydell
        } else {
3970 8900aad2 Peter Maydell
            /* Single to half */
3971 8900aad2 Peter Maydell
            TCGv_i32 tcg_rd = tcg_temp_new_i32();
3972 8900aad2 Peter Maydell
            gen_helper_vfp_fcvt_f32_to_f16(tcg_rd, tcg_rn, cpu_env);
3973 8900aad2 Peter Maydell
            /* write_fp_sreg is OK here because top half of tcg_rd is zero */
3974 8900aad2 Peter Maydell
            write_fp_sreg(s, rd, tcg_rd);
3975 8900aad2 Peter Maydell
            tcg_temp_free_i32(tcg_rd);
3976 8900aad2 Peter Maydell
        }
3977 8900aad2 Peter Maydell
        tcg_temp_free_i32(tcg_rn);
3978 8900aad2 Peter Maydell
        break;
3979 8900aad2 Peter Maydell
    }
3980 8900aad2 Peter Maydell
    case 0x1:
3981 8900aad2 Peter Maydell
    {
3982 8900aad2 Peter Maydell
        TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
3983 8900aad2 Peter Maydell
        TCGv_i32 tcg_rd = tcg_temp_new_i32();
3984 8900aad2 Peter Maydell
        if (dtype == 0) {
3985 8900aad2 Peter Maydell
            /* Double to single */
3986 8900aad2 Peter Maydell
            gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, cpu_env);
3987 8900aad2 Peter Maydell
        } else {
3988 8900aad2 Peter Maydell
            /* Double to half */
3989 8900aad2 Peter Maydell
            gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, cpu_env);
3990 8900aad2 Peter Maydell
            /* write_fp_sreg is OK here because top half of tcg_rd is zero */
3991 8900aad2 Peter Maydell
        }
3992 8900aad2 Peter Maydell
        write_fp_sreg(s, rd, tcg_rd);
3993 8900aad2 Peter Maydell
        tcg_temp_free_i32(tcg_rd);
3994 8900aad2 Peter Maydell
        tcg_temp_free_i64(tcg_rn);
3995 8900aad2 Peter Maydell
        break;
3996 8900aad2 Peter Maydell
    }
3997 8900aad2 Peter Maydell
    case 0x3:
3998 8900aad2 Peter Maydell
    {
3999 8900aad2 Peter Maydell
        TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
4000 8900aad2 Peter Maydell
        tcg_gen_ext16u_i32(tcg_rn, tcg_rn);
4001 8900aad2 Peter Maydell
        if (dtype == 0) {
4002 8900aad2 Peter Maydell
            /* Half to single */
4003 8900aad2 Peter Maydell
            TCGv_i32 tcg_rd = tcg_temp_new_i32();
4004 8900aad2 Peter Maydell
            gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, cpu_env);
4005 8900aad2 Peter Maydell
            write_fp_sreg(s, rd, tcg_rd);
4006 8900aad2 Peter Maydell
            tcg_temp_free_i32(tcg_rd);
4007 8900aad2 Peter Maydell
        } else {
4008 8900aad2 Peter Maydell
            /* Half to double */
4009 8900aad2 Peter Maydell
            TCGv_i64 tcg_rd = tcg_temp_new_i64();
4010 8900aad2 Peter Maydell
            gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, cpu_env);
4011 8900aad2 Peter Maydell
            write_fp_dreg(s, rd, tcg_rd);
4012 8900aad2 Peter Maydell
            tcg_temp_free_i64(tcg_rd);
4013 8900aad2 Peter Maydell
        }
4014 8900aad2 Peter Maydell
        tcg_temp_free_i32(tcg_rn);
4015 8900aad2 Peter Maydell
        break;
4016 8900aad2 Peter Maydell
    }
4017 8900aad2 Peter Maydell
    default:
4018 8900aad2 Peter Maydell
        abort();
4019 8900aad2 Peter Maydell
    }
4020 8900aad2 Peter Maydell
}
4021 8900aad2 Peter Maydell
4022 faa0ba46 Peter Maydell
/* C3.6.25 Floating point data-processing (1 source)
4023 faa0ba46 Peter Maydell
 *   31  30  29 28       24 23  22  21 20    15 14       10 9    5 4    0
4024 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+--------+-----------+------+------+
4025 faa0ba46 Peter Maydell
 * | M | 0 | S | 1 1 1 1 0 | type | 1 | opcode | 1 0 0 0 0 |  Rn  |  Rd  |
4026 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+--------+-----------+------+------+
4027 faa0ba46 Peter Maydell
 */
4028 faa0ba46 Peter Maydell
static void disas_fp_1src(DisasContext *s, uint32_t insn)
4029 faa0ba46 Peter Maydell
{
4030 d9b0848d Peter Maydell
    int type = extract32(insn, 22, 2);
4031 d9b0848d Peter Maydell
    int opcode = extract32(insn, 15, 6);
4032 d9b0848d Peter Maydell
    int rn = extract32(insn, 5, 5);
4033 d9b0848d Peter Maydell
    int rd = extract32(insn, 0, 5);
4034 d9b0848d Peter Maydell
4035 d9b0848d Peter Maydell
    switch (opcode) {
4036 d9b0848d Peter Maydell
    case 0x4: case 0x5: case 0x7:
4037 8900aad2 Peter Maydell
    {
4038 d9b0848d Peter Maydell
        /* FCVT between half, single and double precision */
4039 8900aad2 Peter Maydell
        int dtype = extract32(opcode, 0, 2);
4040 8900aad2 Peter Maydell
        if (type == 2 || dtype == type) {
4041 8900aad2 Peter Maydell
            unallocated_encoding(s);
4042 8900aad2 Peter Maydell
            return;
4043 8900aad2 Peter Maydell
        }
4044 8900aad2 Peter Maydell
        handle_fp_fcvt(s, opcode, rd, rn, dtype, type);
4045 d9b0848d Peter Maydell
        break;
4046 8900aad2 Peter Maydell
    }
4047 d9b0848d Peter Maydell
    case 0x0 ... 0x3:
4048 d9b0848d Peter Maydell
    case 0x8 ... 0xc:
4049 d9b0848d Peter Maydell
    case 0xe ... 0xf:
4050 d9b0848d Peter Maydell
        /* 32-to-32 and 64-to-64 ops */
4051 d9b0848d Peter Maydell
        switch (type) {
4052 d9b0848d Peter Maydell
        case 0:
4053 d9b0848d Peter Maydell
            handle_fp_1src_single(s, opcode, rd, rn);
4054 d9b0848d Peter Maydell
            break;
4055 d9b0848d Peter Maydell
        case 1:
4056 d9b0848d Peter Maydell
            handle_fp_1src_double(s, opcode, rd, rn);
4057 d9b0848d Peter Maydell
            break;
4058 d9b0848d Peter Maydell
        default:
4059 d9b0848d Peter Maydell
            unallocated_encoding(s);
4060 d9b0848d Peter Maydell
        }
4061 d9b0848d Peter Maydell
        break;
4062 d9b0848d Peter Maydell
    default:
4063 d9b0848d Peter Maydell
        unallocated_encoding(s);
4064 d9b0848d Peter Maydell
        break;
4065 d9b0848d Peter Maydell
    }
4066 faa0ba46 Peter Maydell
}
4067 faa0ba46 Peter Maydell
4068 ec73d2e0 Alexander Graf
/* C3.6.26 Floating-point data-processing (2 source) - single precision */
4069 ec73d2e0 Alexander Graf
static void handle_fp_2src_single(DisasContext *s, int opcode,
4070 ec73d2e0 Alexander Graf
                                  int rd, int rn, int rm)
4071 ec73d2e0 Alexander Graf
{
4072 ec73d2e0 Alexander Graf
    TCGv_i32 tcg_op1;
4073 ec73d2e0 Alexander Graf
    TCGv_i32 tcg_op2;
4074 ec73d2e0 Alexander Graf
    TCGv_i32 tcg_res;
4075 ec73d2e0 Alexander Graf
    TCGv_ptr fpst;
4076 ec73d2e0 Alexander Graf
4077 ec73d2e0 Alexander Graf
    tcg_res = tcg_temp_new_i32();
4078 ec73d2e0 Alexander Graf
    fpst = get_fpstatus_ptr();
4079 ec73d2e0 Alexander Graf
    tcg_op1 = read_fp_sreg(s, rn);
4080 ec73d2e0 Alexander Graf
    tcg_op2 = read_fp_sreg(s, rm);
4081 ec73d2e0 Alexander Graf
4082 ec73d2e0 Alexander Graf
    switch (opcode) {
4083 ec73d2e0 Alexander Graf
    case 0x0: /* FMUL */
4084 ec73d2e0 Alexander Graf
        gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
4085 ec73d2e0 Alexander Graf
        break;
4086 ec73d2e0 Alexander Graf
    case 0x1: /* FDIV */
4087 ec73d2e0 Alexander Graf
        gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst);
4088 ec73d2e0 Alexander Graf
        break;
4089 ec73d2e0 Alexander Graf
    case 0x2: /* FADD */
4090 ec73d2e0 Alexander Graf
        gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
4091 ec73d2e0 Alexander Graf
        break;
4092 ec73d2e0 Alexander Graf
    case 0x3: /* FSUB */
4093 ec73d2e0 Alexander Graf
        gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
4094 ec73d2e0 Alexander Graf
        break;
4095 ec73d2e0 Alexander Graf
    case 0x4: /* FMAX */
4096 ec73d2e0 Alexander Graf
        gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
4097 ec73d2e0 Alexander Graf
        break;
4098 ec73d2e0 Alexander Graf
    case 0x5: /* FMIN */
4099 ec73d2e0 Alexander Graf
        gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
4100 ec73d2e0 Alexander Graf
        break;
4101 ec73d2e0 Alexander Graf
    case 0x6: /* FMAXNM */
4102 ec73d2e0 Alexander Graf
        gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
4103 ec73d2e0 Alexander Graf
        break;
4104 ec73d2e0 Alexander Graf
    case 0x7: /* FMINNM */
4105 ec73d2e0 Alexander Graf
        gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
4106 ec73d2e0 Alexander Graf
        break;
4107 ec73d2e0 Alexander Graf
    case 0x8: /* FNMUL */
4108 ec73d2e0 Alexander Graf
        gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
4109 ec73d2e0 Alexander Graf
        gen_helper_vfp_negs(tcg_res, tcg_res);
4110 ec73d2e0 Alexander Graf
        break;
4111 ec73d2e0 Alexander Graf
    }
4112 ec73d2e0 Alexander Graf
4113 ec73d2e0 Alexander Graf
    write_fp_sreg(s, rd, tcg_res);
4114 ec73d2e0 Alexander Graf
4115 ec73d2e0 Alexander Graf
    tcg_temp_free_ptr(fpst);
4116 ec73d2e0 Alexander Graf
    tcg_temp_free_i32(tcg_op1);
4117 ec73d2e0 Alexander Graf
    tcg_temp_free_i32(tcg_op2);
4118 ec73d2e0 Alexander Graf
    tcg_temp_free_i32(tcg_res);
4119 ec73d2e0 Alexander Graf
}
4120 ec73d2e0 Alexander Graf
4121 ec73d2e0 Alexander Graf
/* C3.6.26 Floating-point data-processing (2 source) - double precision */
4122 ec73d2e0 Alexander Graf
static void handle_fp_2src_double(DisasContext *s, int opcode,
4123 ec73d2e0 Alexander Graf
                                  int rd, int rn, int rm)
4124 ec73d2e0 Alexander Graf
{
4125 ec73d2e0 Alexander Graf
    TCGv_i64 tcg_op1;
4126 ec73d2e0 Alexander Graf
    TCGv_i64 tcg_op2;
4127 ec73d2e0 Alexander Graf
    TCGv_i64 tcg_res;
4128 ec73d2e0 Alexander Graf
    TCGv_ptr fpst;
4129 ec73d2e0 Alexander Graf
4130 ec73d2e0 Alexander Graf
    tcg_res = tcg_temp_new_i64();
4131 ec73d2e0 Alexander Graf
    fpst = get_fpstatus_ptr();
4132 ec73d2e0 Alexander Graf
    tcg_op1 = read_fp_dreg(s, rn);
4133 ec73d2e0 Alexander Graf
    tcg_op2 = read_fp_dreg(s, rm);
4134 ec73d2e0 Alexander Graf
4135 ec73d2e0 Alexander Graf
    switch (opcode) {
4136 ec73d2e0 Alexander Graf
    case 0x0: /* FMUL */
4137 ec73d2e0 Alexander Graf
        gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
4138 ec73d2e0 Alexander Graf
        break;
4139 ec73d2e0 Alexander Graf
    case 0x1: /* FDIV */
4140 ec73d2e0 Alexander Graf
        gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst);
4141 ec73d2e0 Alexander Graf
        break;
4142 ec73d2e0 Alexander Graf
    case 0x2: /* FADD */
4143 ec73d2e0 Alexander Graf
        gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
4144 ec73d2e0 Alexander Graf
        break;
4145 ec73d2e0 Alexander Graf
    case 0x3: /* FSUB */
4146 ec73d2e0 Alexander Graf
        gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
4147 ec73d2e0 Alexander Graf
        break;
4148 ec73d2e0 Alexander Graf
    case 0x4: /* FMAX */
4149 ec73d2e0 Alexander Graf
        gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
4150 ec73d2e0 Alexander Graf
        break;
4151 ec73d2e0 Alexander Graf
    case 0x5: /* FMIN */
4152 ec73d2e0 Alexander Graf
        gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
4153 ec73d2e0 Alexander Graf
        break;
4154 ec73d2e0 Alexander Graf
    case 0x6: /* FMAXNM */
4155 ec73d2e0 Alexander Graf
        gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
4156 ec73d2e0 Alexander Graf
        break;
4157 ec73d2e0 Alexander Graf
    case 0x7: /* FMINNM */
4158 ec73d2e0 Alexander Graf
        gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
4159 ec73d2e0 Alexander Graf
        break;
4160 ec73d2e0 Alexander Graf
    case 0x8: /* FNMUL */
4161 ec73d2e0 Alexander Graf
        gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
4162 ec73d2e0 Alexander Graf
        gen_helper_vfp_negd(tcg_res, tcg_res);
4163 ec73d2e0 Alexander Graf
        break;
4164 ec73d2e0 Alexander Graf
    }
4165 ec73d2e0 Alexander Graf
4166 ec73d2e0 Alexander Graf
    write_fp_dreg(s, rd, tcg_res);
4167 ec73d2e0 Alexander Graf
4168 ec73d2e0 Alexander Graf
    tcg_temp_free_ptr(fpst);
4169 ec73d2e0 Alexander Graf
    tcg_temp_free_i64(tcg_op1);
4170 ec73d2e0 Alexander Graf
    tcg_temp_free_i64(tcg_op2);
4171 ec73d2e0 Alexander Graf
    tcg_temp_free_i64(tcg_res);
4172 ec73d2e0 Alexander Graf
}
4173 ec73d2e0 Alexander Graf
4174 faa0ba46 Peter Maydell
/* C3.6.26 Floating point data-processing (2 source)
4175 faa0ba46 Peter Maydell
 *   31  30  29 28       24 23  22  21 20  16 15    12 11 10 9    5 4    0
4176 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
4177 faa0ba46 Peter Maydell
 * | M | 0 | S | 1 1 1 1 0 | type | 1 |  Rm  | opcode | 1 0 |  Rn  |  Rd  |
4178 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
4179 faa0ba46 Peter Maydell
 */
4180 faa0ba46 Peter Maydell
static void disas_fp_2src(DisasContext *s, uint32_t insn)
4181 faa0ba46 Peter Maydell
{
4182 ec73d2e0 Alexander Graf
    int type = extract32(insn, 22, 2);
4183 ec73d2e0 Alexander Graf
    int rd = extract32(insn, 0, 5);
4184 ec73d2e0 Alexander Graf
    int rn = extract32(insn, 5, 5);
4185 ec73d2e0 Alexander Graf
    int rm = extract32(insn, 16, 5);
4186 ec73d2e0 Alexander Graf
    int opcode = extract32(insn, 12, 4);
4187 ec73d2e0 Alexander Graf
4188 ec73d2e0 Alexander Graf
    if (opcode > 8) {
4189 ec73d2e0 Alexander Graf
        unallocated_encoding(s);
4190 ec73d2e0 Alexander Graf
        return;
4191 ec73d2e0 Alexander Graf
    }
4192 ec73d2e0 Alexander Graf
4193 ec73d2e0 Alexander Graf
    switch (type) {
4194 ec73d2e0 Alexander Graf
    case 0:
4195 ec73d2e0 Alexander Graf
        handle_fp_2src_single(s, opcode, rd, rn, rm);
4196 ec73d2e0 Alexander Graf
        break;
4197 ec73d2e0 Alexander Graf
    case 1:
4198 ec73d2e0 Alexander Graf
        handle_fp_2src_double(s, opcode, rd, rn, rm);
4199 ec73d2e0 Alexander Graf
        break;
4200 ec73d2e0 Alexander Graf
    default:
4201 ec73d2e0 Alexander Graf
        unallocated_encoding(s);
4202 ec73d2e0 Alexander Graf
    }
4203 faa0ba46 Peter Maydell
}
4204 faa0ba46 Peter Maydell
4205 6a30667f Alexander Graf
/* C3.6.27 Floating-point data-processing (3 source) - single precision */
4206 6a30667f Alexander Graf
static void handle_fp_3src_single(DisasContext *s, bool o0, bool o1,
4207 6a30667f Alexander Graf
                                  int rd, int rn, int rm, int ra)
4208 6a30667f Alexander Graf
{
4209 6a30667f Alexander Graf
    TCGv_i32 tcg_op1, tcg_op2, tcg_op3;
4210 6a30667f Alexander Graf
    TCGv_i32 tcg_res = tcg_temp_new_i32();
4211 6a30667f Alexander Graf
    TCGv_ptr fpst = get_fpstatus_ptr();
4212 6a30667f Alexander Graf
4213 6a30667f Alexander Graf
    tcg_op1 = read_fp_sreg(s, rn);
4214 6a30667f Alexander Graf
    tcg_op2 = read_fp_sreg(s, rm);
4215 6a30667f Alexander Graf
    tcg_op3 = read_fp_sreg(s, ra);
4216 6a30667f Alexander Graf
4217 6a30667f Alexander Graf
    /* These are fused multiply-add, and must be done as one
4218 6a30667f Alexander Graf
     * floating point operation with no rounding between the
4219 6a30667f Alexander Graf
     * multiplication and addition steps.
4220 6a30667f Alexander Graf
     * NB that doing the negations here as separate steps is
4221 6a30667f Alexander Graf
     * correct : an input NaN should come out with its sign bit
4222 6a30667f Alexander Graf
     * flipped if it is a negated-input.
4223 6a30667f Alexander Graf
     */
4224 6a30667f Alexander Graf
    if (o1 == true) {
4225 6a30667f Alexander Graf
        gen_helper_vfp_negs(tcg_op3, tcg_op3);
4226 6a30667f Alexander Graf
    }
4227 6a30667f Alexander Graf
4228 6a30667f Alexander Graf
    if (o0 != o1) {
4229 6a30667f Alexander Graf
        gen_helper_vfp_negs(tcg_op1, tcg_op1);
4230 6a30667f Alexander Graf
    }
4231 6a30667f Alexander Graf
4232 6a30667f Alexander Graf
    gen_helper_vfp_muladds(tcg_res, tcg_op1, tcg_op2, tcg_op3, fpst);
4233 6a30667f Alexander Graf
4234 6a30667f Alexander Graf
    write_fp_sreg(s, rd, tcg_res);
4235 6a30667f Alexander Graf
4236 6a30667f Alexander Graf
    tcg_temp_free_ptr(fpst);
4237 6a30667f Alexander Graf
    tcg_temp_free_i32(tcg_op1);
4238 6a30667f Alexander Graf
    tcg_temp_free_i32(tcg_op2);
4239 6a30667f Alexander Graf
    tcg_temp_free_i32(tcg_op3);
4240 6a30667f Alexander Graf
    tcg_temp_free_i32(tcg_res);
4241 6a30667f Alexander Graf
}
4242 6a30667f Alexander Graf
4243 6a30667f Alexander Graf
/* C3.6.27 Floating-point data-processing (3 source) - double precision */
4244 6a30667f Alexander Graf
static void handle_fp_3src_double(DisasContext *s, bool o0, bool o1,
4245 6a30667f Alexander Graf
                                  int rd, int rn, int rm, int ra)
4246 6a30667f Alexander Graf
{
4247 6a30667f Alexander Graf
    TCGv_i64 tcg_op1, tcg_op2, tcg_op3;
4248 6a30667f Alexander Graf
    TCGv_i64 tcg_res = tcg_temp_new_i64();
4249 6a30667f Alexander Graf
    TCGv_ptr fpst = get_fpstatus_ptr();
4250 6a30667f Alexander Graf
4251 6a30667f Alexander Graf
    tcg_op1 = read_fp_dreg(s, rn);
4252 6a30667f Alexander Graf
    tcg_op2 = read_fp_dreg(s, rm);
4253 6a30667f Alexander Graf
    tcg_op3 = read_fp_dreg(s, ra);
4254 6a30667f Alexander Graf
4255 6a30667f Alexander Graf
    /* These are fused multiply-add, and must be done as one
4256 6a30667f Alexander Graf
     * floating point operation with no rounding between the
4257 6a30667f Alexander Graf
     * multiplication and addition steps.
4258 6a30667f Alexander Graf
     * NB that doing the negations here as separate steps is
4259 6a30667f Alexander Graf
     * correct : an input NaN should come out with its sign bit
4260 6a30667f Alexander Graf
     * flipped if it is a negated-input.
4261 6a30667f Alexander Graf
     */
4262 6a30667f Alexander Graf
    if (o1 == true) {
4263 6a30667f Alexander Graf
        gen_helper_vfp_negd(tcg_op3, tcg_op3);
4264 6a30667f Alexander Graf
    }
4265 6a30667f Alexander Graf
4266 6a30667f Alexander Graf
    if (o0 != o1) {
4267 6a30667f Alexander Graf
        gen_helper_vfp_negd(tcg_op1, tcg_op1);
4268 6a30667f Alexander Graf
    }
4269 6a30667f Alexander Graf
4270 6a30667f Alexander Graf
    gen_helper_vfp_muladdd(tcg_res, tcg_op1, tcg_op2, tcg_op3, fpst);
4271 6a30667f Alexander Graf
4272 6a30667f Alexander Graf
    write_fp_dreg(s, rd, tcg_res);
4273 6a30667f Alexander Graf
4274 6a30667f Alexander Graf
    tcg_temp_free_ptr(fpst);
4275 6a30667f Alexander Graf
    tcg_temp_free_i64(tcg_op1);
4276 6a30667f Alexander Graf
    tcg_temp_free_i64(tcg_op2);
4277 6a30667f Alexander Graf
    tcg_temp_free_i64(tcg_op3);
4278 6a30667f Alexander Graf
    tcg_temp_free_i64(tcg_res);
4279 6a30667f Alexander Graf
}
4280 6a30667f Alexander Graf
4281 faa0ba46 Peter Maydell
/* C3.6.27 Floating point data-processing (3 source)
4282 faa0ba46 Peter Maydell
 *   31  30  29 28       24 23  22  21  20  16  15  14  10 9    5 4    0
4283 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+----+------+----+------+------+------+
4284 faa0ba46 Peter Maydell
 * | M | 0 | S | 1 1 1 1 1 | type | o1 |  Rm  | o0 |  Ra  |  Rn  |  Rd  |
4285 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+----+------+----+------+------+------+
4286 faa0ba46 Peter Maydell
 */
4287 faa0ba46 Peter Maydell
static void disas_fp_3src(DisasContext *s, uint32_t insn)
4288 faa0ba46 Peter Maydell
{
4289 6a30667f Alexander Graf
    int type = extract32(insn, 22, 2);
4290 6a30667f Alexander Graf
    int rd = extract32(insn, 0, 5);
4291 6a30667f Alexander Graf
    int rn = extract32(insn, 5, 5);
4292 6a30667f Alexander Graf
    int ra = extract32(insn, 10, 5);
4293 6a30667f Alexander Graf
    int rm = extract32(insn, 16, 5);
4294 6a30667f Alexander Graf
    bool o0 = extract32(insn, 15, 1);
4295 6a30667f Alexander Graf
    bool o1 = extract32(insn, 21, 1);
4296 6a30667f Alexander Graf
4297 6a30667f Alexander Graf
    switch (type) {
4298 6a30667f Alexander Graf
    case 0:
4299 6a30667f Alexander Graf
        handle_fp_3src_single(s, o0, o1, rd, rn, rm, ra);
4300 6a30667f Alexander Graf
        break;
4301 6a30667f Alexander Graf
    case 1:
4302 6a30667f Alexander Graf
        handle_fp_3src_double(s, o0, o1, rd, rn, rm, ra);
4303 6a30667f Alexander Graf
        break;
4304 6a30667f Alexander Graf
    default:
4305 6a30667f Alexander Graf
        unallocated_encoding(s);
4306 6a30667f Alexander Graf
    }
4307 faa0ba46 Peter Maydell
}
4308 faa0ba46 Peter Maydell
4309 faa0ba46 Peter Maydell
/* C3.6.28 Floating point immediate
4310 faa0ba46 Peter Maydell
 *   31  30  29 28       24 23  22  21 20        13 12   10 9    5 4    0
4311 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+------------+-------+------+------+
4312 faa0ba46 Peter Maydell
 * | M | 0 | S | 1 1 1 1 0 | type | 1 |    imm8    | 1 0 0 | imm5 |  Rd  |
4313 faa0ba46 Peter Maydell
 * +---+---+---+-----------+------+---+------------+-------+------+------+
4314 faa0ba46 Peter Maydell
 */
4315 faa0ba46 Peter Maydell
static void disas_fp_imm(DisasContext *s, uint32_t insn)
4316 faa0ba46 Peter Maydell
{
4317 6163f868 Alexander Graf
    int rd = extract32(insn, 0, 5);
4318 6163f868 Alexander Graf
    int imm8 = extract32(insn, 13, 8);
4319 6163f868 Alexander Graf
    int is_double = extract32(insn, 22, 2);
4320 6163f868 Alexander Graf
    uint64_t imm;
4321 6163f868 Alexander Graf
    TCGv_i64 tcg_res;
4322 6163f868 Alexander Graf
4323 6163f868 Alexander Graf
    if (is_double > 1) {
4324 6163f868 Alexander Graf
        unallocated_encoding(s);
4325 6163f868 Alexander Graf
        return;
4326 6163f868 Alexander Graf
    }
4327 6163f868 Alexander Graf
4328 6163f868 Alexander Graf
    /* The imm8 encodes the sign bit, enough bits to represent
4329 6163f868 Alexander Graf
     * an exponent in the range 01....1xx to 10....0xx,
4330 6163f868 Alexander Graf
     * and the most significant 4 bits of the mantissa; see
4331 6163f868 Alexander Graf
     * VFPExpandImm() in the v8 ARM ARM.
4332 6163f868 Alexander Graf
     */
4333 6163f868 Alexander Graf
    if (is_double) {
4334 6163f868 Alexander Graf
        imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
4335 6163f868 Alexander Graf
            (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) |
4336 6163f868 Alexander Graf
            extract32(imm8, 0, 6);
4337 6163f868 Alexander Graf
        imm <<= 48;
4338 6163f868 Alexander Graf
    } else {
4339 6163f868 Alexander Graf
        imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
4340 6163f868 Alexander Graf
            (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) |
4341 6163f868 Alexander Graf
            (extract32(imm8, 0, 6) << 3);
4342 6163f868 Alexander Graf
        imm <<= 16;
4343 6163f868 Alexander Graf
    }
4344 6163f868 Alexander Graf
4345 6163f868 Alexander Graf
    tcg_res = tcg_const_i64(imm);
4346 6163f868 Alexander Graf
    write_fp_dreg(s, rd, tcg_res);
4347 6163f868 Alexander Graf
    tcg_temp_free_i64(tcg_res);
4348 faa0ba46 Peter Maydell
}
4349 faa0ba46 Peter Maydell
4350 52a1f6a3 Alexander Graf
/* Handle floating point <=> fixed point conversions. Note that we can
4351 52a1f6a3 Alexander Graf
 * also deal with fp <=> integer conversions as a special case (scale == 64)
4352 52a1f6a3 Alexander Graf
 * OPTME: consider handling that special case specially or at least skipping
4353 52a1f6a3 Alexander Graf
 * the call to scalbn in the helpers for zero shifts.
4354 52a1f6a3 Alexander Graf
 */
4355 52a1f6a3 Alexander Graf
static void handle_fpfpcvt(DisasContext *s, int rd, int rn, int opcode,
4356 52a1f6a3 Alexander Graf
                           bool itof, int rmode, int scale, int sf, int type)
4357 52a1f6a3 Alexander Graf
{
4358 52a1f6a3 Alexander Graf
    bool is_signed = !(opcode & 1);
4359 52a1f6a3 Alexander Graf
    bool is_double = type;
4360 52a1f6a3 Alexander Graf
    TCGv_ptr tcg_fpstatus;
4361 52a1f6a3 Alexander Graf
    TCGv_i32 tcg_shift;
4362 52a1f6a3 Alexander Graf
4363 52a1f6a3 Alexander Graf
    tcg_fpstatus = get_fpstatus_ptr();
4364 52a1f6a3 Alexander Graf
4365 52a1f6a3 Alexander Graf
    tcg_shift = tcg_const_i32(64 - scale);
4366 52a1f6a3 Alexander Graf
4367 52a1f6a3 Alexander Graf
    if (itof) {
4368 52a1f6a3 Alexander Graf
        TCGv_i64 tcg_int = cpu_reg(s, rn);
4369 52a1f6a3 Alexander Graf
        if (!sf) {
4370 52a1f6a3 Alexander Graf
            TCGv_i64 tcg_extend = new_tmp_a64(s);
4371 52a1f6a3 Alexander Graf
4372 52a1f6a3 Alexander Graf
            if (is_signed) {
4373 52a1f6a3 Alexander Graf
                tcg_gen_ext32s_i64(tcg_extend, tcg_int);
4374 52a1f6a3 Alexander Graf
            } else {
4375 52a1f6a3 Alexander Graf
                tcg_gen_ext32u_i64(tcg_extend, tcg_int);
4376 52a1f6a3 Alexander Graf
            }
4377 52a1f6a3 Alexander Graf
4378 52a1f6a3 Alexander Graf
            tcg_int = tcg_extend;
4379 52a1f6a3 Alexander Graf
        }
4380 52a1f6a3 Alexander Graf
4381 52a1f6a3 Alexander Graf
        if (is_double) {
4382 52a1f6a3 Alexander Graf
            TCGv_i64 tcg_double = tcg_temp_new_i64();
4383 52a1f6a3 Alexander Graf
            if (is_signed) {
4384 52a1f6a3 Alexander Graf
                gen_helper_vfp_sqtod(tcg_double, tcg_int,
4385 52a1f6a3 Alexander Graf
                                     tcg_shift, tcg_fpstatus);
4386 52a1f6a3 Alexander Graf
            } else {
4387 52a1f6a3 Alexander Graf
                gen_helper_vfp_uqtod(tcg_double, tcg_int,
4388 52a1f6a3 Alexander Graf
                                     tcg_shift, tcg_fpstatus);
4389 52a1f6a3 Alexander Graf
            }
4390 52a1f6a3 Alexander Graf
            write_fp_dreg(s, rd, tcg_double);
4391 52a1f6a3 Alexander Graf
            tcg_temp_free_i64(tcg_double);
4392 52a1f6a3 Alexander Graf
        } else {
4393 52a1f6a3 Alexander Graf
            TCGv_i32 tcg_single = tcg_temp_new_i32();
4394 52a1f6a3 Alexander Graf
            if (is_signed) {
4395 52a1f6a3 Alexander Graf
                gen_helper_vfp_sqtos(tcg_single, tcg_int,
4396 52a1f6a3 Alexander Graf
                                     tcg_shift, tcg_fpstatus);
4397 52a1f6a3 Alexander Graf
            } else {
4398 52a1f6a3 Alexander Graf
                gen_helper_vfp_uqtos(tcg_single, tcg_int,
4399 52a1f6a3 Alexander Graf
                                     tcg_shift, tcg_fpstatus);
4400 52a1f6a3 Alexander Graf
            }
4401 52a1f6a3 Alexander Graf
            write_fp_sreg(s, rd, tcg_single);
4402 52a1f6a3 Alexander Graf
            tcg_temp_free_i32(tcg_single);
4403 52a1f6a3 Alexander Graf
        }
4404 52a1f6a3 Alexander Graf
    } else {
4405 52a1f6a3 Alexander Graf
        TCGv_i64 tcg_int = cpu_reg(s, rd);
4406 52a1f6a3 Alexander Graf
        TCGv_i32 tcg_rmode;
4407 52a1f6a3 Alexander Graf
4408 52a1f6a3 Alexander Graf
        if (extract32(opcode, 2, 1)) {
4409 52a1f6a3 Alexander Graf
            /* There are too many rounding modes to all fit into rmode,
4410 52a1f6a3 Alexander Graf
             * so FCVTA[US] is a special case.
4411 52a1f6a3 Alexander Graf
             */
4412 52a1f6a3 Alexander Graf
            rmode = FPROUNDING_TIEAWAY;
4413 52a1f6a3 Alexander Graf
        }
4414 52a1f6a3 Alexander Graf
4415 52a1f6a3 Alexander Graf
        tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
4416 52a1f6a3 Alexander Graf
4417 52a1f6a3 Alexander Graf
        gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
4418 52a1f6a3 Alexander Graf
4419 52a1f6a3 Alexander Graf
        if (is_double) {
4420 52a1f6a3 Alexander Graf
            TCGv_i64 tcg_double = read_fp_dreg(s, rn);
4421 52a1f6a3 Alexander Graf
            if (is_signed) {
4422 52a1f6a3 Alexander Graf
                if (!sf) {
4423 52a1f6a3 Alexander Graf
                    gen_helper_vfp_tosld(tcg_int, tcg_double,
4424 52a1f6a3 Alexander Graf
                                         tcg_shift, tcg_fpstatus);
4425 52a1f6a3 Alexander Graf
                } else {
4426 52a1f6a3 Alexander Graf
                    gen_helper_vfp_tosqd(tcg_int, tcg_double,
4427 52a1f6a3 Alexander Graf
                                         tcg_shift, tcg_fpstatus);
4428 52a1f6a3 Alexander Graf
                }
4429 52a1f6a3 Alexander Graf
            } else {
4430 52a1f6a3 Alexander Graf
                if (!sf) {
4431 52a1f6a3 Alexander Graf
                    gen_helper_vfp_tould(tcg_int, tcg_double,
4432 52a1f6a3 Alexander Graf
                                         tcg_shift, tcg_fpstatus);
4433 52a1f6a3 Alexander Graf
                } else {
4434 52a1f6a3 Alexander Graf
                    gen_helper_vfp_touqd(tcg_int, tcg_double,
4435 52a1f6a3 Alexander Graf
                                         tcg_shift, tcg_fpstatus);
4436 52a1f6a3 Alexander Graf
                }
4437 52a1f6a3 Alexander Graf
            }
4438 52a1f6a3 Alexander Graf
            tcg_temp_free_i64(tcg_double);
4439 52a1f6a3 Alexander Graf
        } else {
4440 52a1f6a3 Alexander Graf
            TCGv_i32 tcg_single = read_fp_sreg(s, rn);
4441 52a1f6a3 Alexander Graf
            if (sf) {
4442 52a1f6a3 Alexander Graf
                if (is_signed) {
4443 52a1f6a3 Alexander Graf
                    gen_helper_vfp_tosqs(tcg_int, tcg_single,
4444 52a1f6a3 Alexander Graf
                                         tcg_shift, tcg_fpstatus);
4445 52a1f6a3 Alexander Graf
                } else {
4446 52a1f6a3 Alexander Graf
                    gen_helper_vfp_touqs(tcg_int, tcg_single,
4447 52a1f6a3 Alexander Graf
                                         tcg_shift, tcg_fpstatus);
4448 52a1f6a3 Alexander Graf
                }
4449 52a1f6a3 Alexander Graf
            } else {
4450 52a1f6a3 Alexander Graf
                TCGv_i32 tcg_dest = tcg_temp_new_i32();
4451 52a1f6a3 Alexander Graf
                if (is_signed) {
4452 52a1f6a3 Alexander Graf
                    gen_helper_vfp_tosls(tcg_dest, tcg_single,
4453 52a1f6a3 Alexander Graf
                                         tcg_shift, tcg_fpstatus);
4454 52a1f6a3 Alexander Graf
                } else {
4455 52a1f6a3 Alexander Graf
                    gen_helper_vfp_touls(tcg_dest, tcg_single,
4456 52a1f6a3 Alexander Graf
                                         tcg_shift, tcg_fpstatus);
4457 52a1f6a3 Alexander Graf
                }
4458 52a1f6a3 Alexander Graf
                tcg_gen_extu_i32_i64(tcg_int, tcg_dest);
4459 52a1f6a3 Alexander Graf
                tcg_temp_free_i32(tcg_dest);
4460 52a1f6a3 Alexander Graf
            }
4461 52a1f6a3 Alexander Graf
            tcg_temp_free_i32(tcg_single);
4462 52a1f6a3 Alexander Graf
        }
4463 52a1f6a3 Alexander Graf
4464 52a1f6a3 Alexander Graf
        gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
4465 52a1f6a3 Alexander Graf
        tcg_temp_free_i32(tcg_rmode);
4466 52a1f6a3 Alexander Graf
4467 52a1f6a3 Alexander Graf
        if (!sf) {
4468 52a1f6a3 Alexander Graf
            tcg_gen_ext32u_i64(tcg_int, tcg_int);
4469 52a1f6a3 Alexander Graf
        }
4470 52a1f6a3 Alexander Graf
    }
4471 52a1f6a3 Alexander Graf
4472 52a1f6a3 Alexander Graf
    tcg_temp_free_ptr(tcg_fpstatus);
4473 52a1f6a3 Alexander Graf
    tcg_temp_free_i32(tcg_shift);
4474 52a1f6a3 Alexander Graf
}
4475 52a1f6a3 Alexander Graf
4476 faa0ba46 Peter Maydell
/* C3.6.29 Floating point <-> fixed point conversions
4477 faa0ba46 Peter Maydell
 *   31   30  29 28       24 23  22  21 20   19 18    16 15   10 9    5 4    0
4478 faa0ba46 Peter Maydell
 * +----+---+---+-----------+------+---+-------+--------+-------+------+------+
4479 faa0ba46 Peter Maydell
 * | sf | 0 | S | 1 1 1 1 0 | type | 0 | rmode | opcode | scale |  Rn  |  Rd  |
4480 faa0ba46 Peter Maydell
 * +----+---+---+-----------+------+---+-------+--------+-------+------+------+
4481 faa0ba46 Peter Maydell
 */
4482 faa0ba46 Peter Maydell
static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn)
4483 faa0ba46 Peter Maydell
{
4484 52a1f6a3 Alexander Graf
    int rd = extract32(insn, 0, 5);
4485 52a1f6a3 Alexander Graf
    int rn = extract32(insn, 5, 5);
4486 52a1f6a3 Alexander Graf
    int scale = extract32(insn, 10, 6);
4487 52a1f6a3 Alexander Graf
    int opcode = extract32(insn, 16, 3);
4488 52a1f6a3 Alexander Graf
    int rmode = extract32(insn, 19, 2);
4489 52a1f6a3 Alexander Graf
    int type = extract32(insn, 22, 2);
4490 52a1f6a3 Alexander Graf
    bool sbit = extract32(insn, 29, 1);
4491 52a1f6a3 Alexander Graf
    bool sf = extract32(insn, 31, 1);
4492 52a1f6a3 Alexander Graf
    bool itof;
4493 52a1f6a3 Alexander Graf
4494 52a1f6a3 Alexander Graf
    if (sbit || (type > 1)
4495 52a1f6a3 Alexander Graf
        || (!sf && scale < 32)) {
4496 52a1f6a3 Alexander Graf
        unallocated_encoding(s);
4497 52a1f6a3 Alexander Graf
        return;
4498 52a1f6a3 Alexander Graf
    }
4499 52a1f6a3 Alexander Graf
4500 52a1f6a3 Alexander Graf
    switch ((rmode << 3) | opcode) {
4501 52a1f6a3 Alexander Graf
    case 0x2: /* SCVTF */
4502 52a1f6a3 Alexander Graf
    case 0x3: /* UCVTF */
4503 52a1f6a3 Alexander Graf
        itof = true;
4504 52a1f6a3 Alexander Graf
        break;
4505 52a1f6a3 Alexander Graf
    case 0x18: /* FCVTZS */
4506 52a1f6a3 Alexander Graf
    case 0x19: /* FCVTZU */
4507 52a1f6a3 Alexander Graf
        itof = false;
4508 52a1f6a3 Alexander Graf
        break;
4509 52a1f6a3 Alexander Graf
    default:
4510 52a1f6a3 Alexander Graf
        unallocated_encoding(s);
4511 52a1f6a3 Alexander Graf
        return;
4512 52a1f6a3 Alexander Graf
    }
4513 52a1f6a3 Alexander Graf
4514 52a1f6a3 Alexander Graf
    handle_fpfpcvt(s, rd, rn, opcode, itof, FPROUNDING_ZERO, scale, sf, type);
4515 faa0ba46 Peter Maydell
}
4516 faa0ba46 Peter Maydell
4517 ce5458e8 Peter Maydell
static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
4518 ce5458e8 Peter Maydell
{
4519 ce5458e8 Peter Maydell
    /* FMOV: gpr to or from float, double, or top half of quad fp reg,
4520 ce5458e8 Peter Maydell
     * without conversion.
4521 ce5458e8 Peter Maydell
     */
4522 ce5458e8 Peter Maydell
4523 ce5458e8 Peter Maydell
    if (itof) {
4524 ce5458e8 Peter Maydell
        TCGv_i64 tcg_rn = cpu_reg(s, rn);
4525 ce5458e8 Peter Maydell
4526 ce5458e8 Peter Maydell
        switch (type) {
4527 ce5458e8 Peter Maydell
        case 0:
4528 ce5458e8 Peter Maydell
        {
4529 ce5458e8 Peter Maydell
            /* 32 bit */
4530 ce5458e8 Peter Maydell
            TCGv_i64 tmp = tcg_temp_new_i64();
4531 ce5458e8 Peter Maydell
            tcg_gen_ext32u_i64(tmp, tcg_rn);
4532 e2f90565 Peter Maydell
            tcg_gen_st_i64(tmp, cpu_env, fp_reg_offset(rd, MO_64));
4533 ce5458e8 Peter Maydell
            tcg_gen_movi_i64(tmp, 0);
4534 e2f90565 Peter Maydell
            tcg_gen_st_i64(tmp, cpu_env, fp_reg_hi_offset(rd));
4535 ce5458e8 Peter Maydell
            tcg_temp_free_i64(tmp);
4536 ce5458e8 Peter Maydell
            break;
4537 ce5458e8 Peter Maydell
        }
4538 ce5458e8 Peter Maydell
        case 1:
4539 ce5458e8 Peter Maydell
        {
4540 ce5458e8 Peter Maydell
            /* 64 bit */
4541 ce5458e8 Peter Maydell
            TCGv_i64 tmp = tcg_const_i64(0);
4542 e2f90565 Peter Maydell
            tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_offset(rd, MO_64));
4543 e2f90565 Peter Maydell
            tcg_gen_st_i64(tmp, cpu_env, fp_reg_hi_offset(rd));
4544 ce5458e8 Peter Maydell
            tcg_temp_free_i64(tmp);
4545 ce5458e8 Peter Maydell
            break;
4546 ce5458e8 Peter Maydell
        }
4547 ce5458e8 Peter Maydell
        case 2:
4548 ce5458e8 Peter Maydell
            /* 64 bit to top half. */
4549 e2f90565 Peter Maydell
            tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_hi_offset(rd));
4550 ce5458e8 Peter Maydell
            break;
4551 ce5458e8 Peter Maydell
        }
4552 ce5458e8 Peter Maydell
    } else {
4553 ce5458e8 Peter Maydell
        TCGv_i64 tcg_rd = cpu_reg(s, rd);
4554 ce5458e8 Peter Maydell
4555 ce5458e8 Peter Maydell
        switch (type) {
4556 ce5458e8 Peter Maydell
        case 0:
4557 ce5458e8 Peter Maydell
            /* 32 bit */
4558 e2f90565 Peter Maydell
            tcg_gen_ld32u_i64(tcg_rd, cpu_env, fp_reg_offset(rn, MO_32));
4559 ce5458e8 Peter Maydell
            break;
4560 ce5458e8 Peter Maydell
        case 1:
4561 ce5458e8 Peter Maydell
            /* 64 bit */
4562 e2f90565 Peter Maydell
            tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_offset(rn, MO_64));
4563 e2f90565 Peter Maydell
            break;
4564 e2f90565 Peter Maydell
        case 2:
4565 e2f90565 Peter Maydell
            /* 64 bits from top half */
4566 e2f90565 Peter Maydell
            tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_hi_offset(rn));
4567 ce5458e8 Peter Maydell
            break;
4568 ce5458e8 Peter Maydell
        }
4569 ce5458e8 Peter Maydell
    }
4570 ce5458e8 Peter Maydell
}
4571 ce5458e8 Peter Maydell
4572 faa0ba46 Peter Maydell
/* C3.6.30 Floating point <-> integer conversions
4573 faa0ba46 Peter Maydell
 *   31   30  29 28       24 23  22  21 20   19 18 16 15         10 9  5 4  0
4574 faa0ba46 Peter Maydell
 * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
4575 c436d406 Will Newton
 * | sf | 0 | S | 1 1 1 1 0 | type | 1 | rmode | opc | 0 0 0 0 0 0 | Rn | Rd |
4576 faa0ba46 Peter Maydell
 * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
4577 faa0ba46 Peter Maydell
 */
4578 faa0ba46 Peter Maydell
static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
4579 faa0ba46 Peter Maydell
{
4580 ce5458e8 Peter Maydell
    int rd = extract32(insn, 0, 5);
4581 ce5458e8 Peter Maydell
    int rn = extract32(insn, 5, 5);
4582 ce5458e8 Peter Maydell
    int opcode = extract32(insn, 16, 3);
4583 ce5458e8 Peter Maydell
    int rmode = extract32(insn, 19, 2);
4584 ce5458e8 Peter Maydell
    int type = extract32(insn, 22, 2);
4585 ce5458e8 Peter Maydell
    bool sbit = extract32(insn, 29, 1);
4586 ce5458e8 Peter Maydell
    bool sf = extract32(insn, 31, 1);
4587 ce5458e8 Peter Maydell
4588 c436d406 Will Newton
    if (sbit) {
4589 c436d406 Will Newton
        unallocated_encoding(s);
4590 c436d406 Will Newton
        return;
4591 c436d406 Will Newton
    }
4592 c436d406 Will Newton
4593 c436d406 Will Newton
    if (opcode > 5) {
4594 ce5458e8 Peter Maydell
        /* FMOV */
4595 ce5458e8 Peter Maydell
        bool itof = opcode & 1;
4596 ce5458e8 Peter Maydell
4597 c436d406 Will Newton
        if (rmode >= 2) {
4598 c436d406 Will Newton
            unallocated_encoding(s);
4599 c436d406 Will Newton
            return;
4600 c436d406 Will Newton
        }
4601 c436d406 Will Newton
4602 ce5458e8 Peter Maydell
        switch (sf << 3 | type << 1 | rmode) {
4603 ce5458e8 Peter Maydell
        case 0x0: /* 32 bit */
4604 ce5458e8 Peter Maydell
        case 0xa: /* 64 bit */
4605 ce5458e8 Peter Maydell
        case 0xd: /* 64 bit to top half of quad */
4606 ce5458e8 Peter Maydell
            break;
4607 ce5458e8 Peter Maydell
        default:
4608 ce5458e8 Peter Maydell
            /* all other sf/type/rmode combinations are invalid */
4609 ce5458e8 Peter Maydell
            unallocated_encoding(s);
4610 ce5458e8 Peter Maydell
            break;
4611 ce5458e8 Peter Maydell
        }
4612 ce5458e8 Peter Maydell
4613 ce5458e8 Peter Maydell
        handle_fmov(s, rd, rn, type, itof);
4614 ce5458e8 Peter Maydell
    } else {
4615 ce5458e8 Peter Maydell
        /* actual FP conversions */
4616 c436d406 Will Newton
        bool itof = extract32(opcode, 1, 1);
4617 c436d406 Will Newton
4618 c436d406 Will Newton
        if (type > 1 || (rmode != 0 && opcode > 1)) {
4619 c436d406 Will Newton
            unallocated_encoding(s);
4620 c436d406 Will Newton
            return;
4621 c436d406 Will Newton
        }
4622 c436d406 Will Newton
4623 c436d406 Will Newton
        handle_fpfpcvt(s, rd, rn, opcode, itof, rmode, 64, sf, type);
4624 ce5458e8 Peter Maydell
    }
4625 faa0ba46 Peter Maydell
}
4626 faa0ba46 Peter Maydell
4627 faa0ba46 Peter Maydell
/* FP-specific subcases of table C3-6 (SIMD and FP data processing)
4628 faa0ba46 Peter Maydell
 *   31  30  29 28     25 24                          0
4629 faa0ba46 Peter Maydell
 * +---+---+---+---------+-----------------------------+
4630 faa0ba46 Peter Maydell
 * |   | 0 |   | 1 1 1 1 |                             |
4631 faa0ba46 Peter Maydell
 * +---+---+---+---------+-----------------------------+
4632 faa0ba46 Peter Maydell
 */
4633 faa0ba46 Peter Maydell
static void disas_data_proc_fp(DisasContext *s, uint32_t insn)
4634 faa0ba46 Peter Maydell
{
4635 faa0ba46 Peter Maydell
    if (extract32(insn, 24, 1)) {
4636 faa0ba46 Peter Maydell
        /* Floating point data-processing (3 source) */
4637 faa0ba46 Peter Maydell
        disas_fp_3src(s, insn);
4638 faa0ba46 Peter Maydell
    } else if (extract32(insn, 21, 1) == 0) {
4639 faa0ba46 Peter Maydell
        /* Floating point to fixed point conversions */
4640 faa0ba46 Peter Maydell
        disas_fp_fixed_conv(s, insn);
4641 faa0ba46 Peter Maydell
    } else {
4642 faa0ba46 Peter Maydell
        switch (extract32(insn, 10, 2)) {
4643 faa0ba46 Peter Maydell
        case 1:
4644 faa0ba46 Peter Maydell
            /* Floating point conditional compare */
4645 faa0ba46 Peter Maydell
            disas_fp_ccomp(s, insn);
4646 faa0ba46 Peter Maydell
            break;
4647 faa0ba46 Peter Maydell
        case 2:
4648 faa0ba46 Peter Maydell
            /* Floating point data-processing (2 source) */
4649 faa0ba46 Peter Maydell
            disas_fp_2src(s, insn);
4650 faa0ba46 Peter Maydell
            break;
4651 faa0ba46 Peter Maydell
        case 3:
4652 faa0ba46 Peter Maydell
            /* Floating point conditional select */
4653 faa0ba46 Peter Maydell
            disas_fp_csel(s, insn);
4654 faa0ba46 Peter Maydell
            break;
4655 faa0ba46 Peter Maydell
        case 0:
4656 faa0ba46 Peter Maydell
            switch (ctz32(extract32(insn, 12, 4))) {
4657 faa0ba46 Peter Maydell
            case 0: /* [15:12] == xxx1 */
4658 faa0ba46 Peter Maydell
                /* Floating point immediate */
4659 faa0ba46 Peter Maydell
                disas_fp_imm(s, insn);
4660 faa0ba46 Peter Maydell
                break;
4661 faa0ba46 Peter Maydell
            case 1: /* [15:12] == xx10 */
4662 faa0ba46 Peter Maydell
                /* Floating point compare */
4663 faa0ba46 Peter Maydell
                disas_fp_compare(s, insn);
4664 faa0ba46 Peter Maydell
                break;
4665 faa0ba46 Peter Maydell
            case 2: /* [15:12] == x100 */
4666 faa0ba46 Peter Maydell
                /* Floating point data-processing (1 source) */
4667 faa0ba46 Peter Maydell
                disas_fp_1src(s, insn);
4668 faa0ba46 Peter Maydell
                break;
4669 faa0ba46 Peter Maydell
            case 3: /* [15:12] == 1000 */
4670 faa0ba46 Peter Maydell
                unallocated_encoding(s);
4671 faa0ba46 Peter Maydell
                break;
4672 faa0ba46 Peter Maydell
            default: /* [15:12] == 0000 */
4673 faa0ba46 Peter Maydell
                /* Floating point <-> integer conversions */
4674 faa0ba46 Peter Maydell
                disas_fp_int_conv(s, insn);
4675 faa0ba46 Peter Maydell
                break;
4676 faa0ba46 Peter Maydell
            }
4677 faa0ba46 Peter Maydell
            break;
4678 faa0ba46 Peter Maydell
        }
4679 faa0ba46 Peter Maydell
    }
4680 faa0ba46 Peter Maydell
}
4681 faa0ba46 Peter Maydell
4682 5c73747f Peter Maydell
static void do_ext64(DisasContext *s, TCGv_i64 tcg_left, TCGv_i64 tcg_right,
4683 5c73747f Peter Maydell
                     int pos)
4684 5c73747f Peter Maydell
{
4685 5c73747f Peter Maydell
    /* Extract 64 bits from the middle of two concatenated 64 bit
4686 5c73747f Peter Maydell
     * vector register slices left:right. The extracted bits start
4687 5c73747f Peter Maydell
     * at 'pos' bits into the right (least significant) side.
4688 5c73747f Peter Maydell
     * We return the result in tcg_right, and guarantee not to
4689 5c73747f Peter Maydell
     * trash tcg_left.
4690 5c73747f Peter Maydell
     */
4691 5c73747f Peter Maydell
    TCGv_i64 tcg_tmp = tcg_temp_new_i64();
4692 5c73747f Peter Maydell
    assert(pos > 0 && pos < 64);
4693 5c73747f Peter Maydell
4694 5c73747f Peter Maydell
    tcg_gen_shri_i64(tcg_right, tcg_right, pos);
4695 5c73747f Peter Maydell
    tcg_gen_shli_i64(tcg_tmp, tcg_left, 64 - pos);
4696 5c73747f Peter Maydell
    tcg_gen_or_i64(tcg_right, tcg_right, tcg_tmp);
4697 5c73747f Peter Maydell
4698 5c73747f Peter Maydell
    tcg_temp_free_i64(tcg_tmp);
4699 5c73747f Peter Maydell
}
4700 5c73747f Peter Maydell
4701 384b26fb Alex Bennée
/* C3.6.1 EXT
4702 384b26fb Alex Bennée
 *   31  30 29         24 23 22  21 20  16 15  14  11 10  9    5 4    0
4703 384b26fb Alex Bennée
 * +---+---+-------------+-----+---+------+---+------+---+------+------+
4704 384b26fb Alex Bennée
 * | 0 | Q | 1 0 1 1 1 0 | op2 | 0 |  Rm  | 0 | imm4 | 0 |  Rn  |  Rd  |
4705 384b26fb Alex Bennée
 * +---+---+-------------+-----+---+------+---+------+---+------+------+
4706 384b26fb Alex Bennée
 */
4707 384b26fb Alex Bennée
static void disas_simd_ext(DisasContext *s, uint32_t insn)
4708 384b26fb Alex Bennée
{
4709 5c73747f Peter Maydell
    int is_q = extract32(insn, 30, 1);
4710 5c73747f Peter Maydell
    int op2 = extract32(insn, 22, 2);
4711 5c73747f Peter Maydell
    int imm4 = extract32(insn, 11, 4);
4712 5c73747f Peter Maydell
    int rm = extract32(insn, 16, 5);
4713 5c73747f Peter Maydell
    int rn = extract32(insn, 5, 5);
4714 5c73747f Peter Maydell
    int rd = extract32(insn, 0, 5);
4715 5c73747f Peter Maydell
    int pos = imm4 << 3;
4716 5c73747f Peter Maydell
    TCGv_i64 tcg_resl, tcg_resh;
4717 5c73747f Peter Maydell
4718 5c73747f Peter Maydell
    if (op2 != 0 || (!is_q && extract32(imm4, 3, 1))) {
4719 5c73747f Peter Maydell
        unallocated_encoding(s);
4720 5c73747f Peter Maydell
        return;
4721 5c73747f Peter Maydell
    }
4722 5c73747f Peter Maydell
4723 5c73747f Peter Maydell
    tcg_resh = tcg_temp_new_i64();
4724 5c73747f Peter Maydell
    tcg_resl = tcg_temp_new_i64();
4725 5c73747f Peter Maydell
4726 5c73747f Peter Maydell
    /* Vd gets bits starting at pos bits into Vm:Vn. This is
4727 5c73747f Peter Maydell
     * either extracting 128 bits from a 128:128 concatenation, or
4728 5c73747f Peter Maydell
     * extracting 64 bits from a 64:64 concatenation.
4729 5c73747f Peter Maydell
     */
4730 5c73747f Peter Maydell
    if (!is_q) {
4731 5c73747f Peter Maydell
        read_vec_element(s, tcg_resl, rn, 0, MO_64);
4732 5c73747f Peter Maydell
        if (pos != 0) {
4733 5c73747f Peter Maydell
            read_vec_element(s, tcg_resh, rm, 0, MO_64);
4734 5c73747f Peter Maydell
            do_ext64(s, tcg_resh, tcg_resl, pos);
4735 5c73747f Peter Maydell
        }
4736 5c73747f Peter Maydell
        tcg_gen_movi_i64(tcg_resh, 0);
4737 5c73747f Peter Maydell
    } else {
4738 5c73747f Peter Maydell
        TCGv_i64 tcg_hh;
4739 5c73747f Peter Maydell
        typedef struct {
4740 5c73747f Peter Maydell
            int reg;
4741 5c73747f Peter Maydell
            int elt;
4742 5c73747f Peter Maydell
        } EltPosns;
4743 5c73747f Peter Maydell
        EltPosns eltposns[] = { {rn, 0}, {rn, 1}, {rm, 0}, {rm, 1} };
4744 5c73747f Peter Maydell
        EltPosns *elt = eltposns;
4745 5c73747f Peter Maydell
4746 5c73747f Peter Maydell
        if (pos >= 64) {
4747 5c73747f Peter Maydell
            elt++;
4748 5c73747f Peter Maydell
            pos -= 64;
4749 5c73747f Peter Maydell
        }
4750 5c73747f Peter Maydell
4751 5c73747f Peter Maydell
        read_vec_element(s, tcg_resl, elt->reg, elt->elt, MO_64);
4752 5c73747f Peter Maydell
        elt++;
4753 5c73747f Peter Maydell
        read_vec_element(s, tcg_resh, elt->reg, elt->elt, MO_64);
4754 5c73747f Peter Maydell
        elt++;
4755 5c73747f Peter Maydell
        if (pos != 0) {
4756 5c73747f Peter Maydell
            do_ext64(s, tcg_resh, tcg_resl, pos);
4757 5c73747f Peter Maydell
            tcg_hh = tcg_temp_new_i64();
4758 5c73747f Peter Maydell
            read_vec_element(s, tcg_hh, elt->reg, elt->elt, MO_64);
4759 5c73747f Peter Maydell
            do_ext64(s, tcg_hh, tcg_resh, pos);
4760 5c73747f Peter Maydell
            tcg_temp_free_i64(tcg_hh);
4761 5c73747f Peter Maydell
        }
4762 5c73747f Peter Maydell
    }
4763 5c73747f Peter Maydell
4764 5c73747f Peter Maydell
    write_vec_element(s, tcg_resl, rd, 0, MO_64);
4765 5c73747f Peter Maydell
    tcg_temp_free_i64(tcg_resl);
4766 5c73747f Peter Maydell
    write_vec_element(s, tcg_resh, rd, 1, MO_64);
4767 5c73747f Peter Maydell
    tcg_temp_free_i64(tcg_resh);
4768 384b26fb Alex Bennée
}
4769 384b26fb Alex Bennée
4770 384b26fb Alex Bennée
/* C3.6.2 TBL/TBX
4771 384b26fb Alex Bennée
 *   31  30 29         24 23 22  21 20  16 15  14 13  12  11 10 9    5 4    0
4772 384b26fb Alex Bennée
 * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+
4773 384b26fb Alex Bennée
 * | 0 | Q | 0 0 1 1 1 0 | op2 | 0 |  Rm  | 0 | len | op | 0 0 |  Rn  |  Rd  |
4774 384b26fb Alex Bennée
 * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+
4775 384b26fb Alex Bennée
 */
4776 384b26fb Alex Bennée
static void disas_simd_tb(DisasContext *s, uint32_t insn)
4777 384b26fb Alex Bennée
{
4778 7c51048f Michael Matz
    int op2 = extract32(insn, 22, 2);
4779 7c51048f Michael Matz
    int is_q = extract32(insn, 30, 1);
4780 7c51048f Michael Matz
    int rm = extract32(insn, 16, 5);
4781 7c51048f Michael Matz
    int rn = extract32(insn, 5, 5);
4782 7c51048f Michael Matz
    int rd = extract32(insn, 0, 5);
4783 7c51048f Michael Matz
    int is_tblx = extract32(insn, 12, 1);
4784 7c51048f Michael Matz
    int len = extract32(insn, 13, 2);
4785 7c51048f Michael Matz
    TCGv_i64 tcg_resl, tcg_resh, tcg_idx;
4786 7c51048f Michael Matz
    TCGv_i32 tcg_regno, tcg_numregs;
4787 7c51048f Michael Matz
4788 7c51048f Michael Matz
    if (op2 != 0) {
4789 7c51048f Michael Matz
        unallocated_encoding(s);
4790 7c51048f Michael Matz
        return;
4791 7c51048f Michael Matz
    }
4792 7c51048f Michael Matz
4793 7c51048f Michael Matz
    /* This does a table lookup: for every byte element in the input
4794 7c51048f Michael Matz
     * we index into a table formed from up to four vector registers,
4795 7c51048f Michael Matz
     * and then the output is the result of the lookups. Our helper
4796 7c51048f Michael Matz
     * function does the lookup operation for a single 64 bit part of
4797 7c51048f Michael Matz
     * the input.
4798 7c51048f Michael Matz
     */
4799 7c51048f Michael Matz
    tcg_resl = tcg_temp_new_i64();
4800 7c51048f Michael Matz
    tcg_resh = tcg_temp_new_i64();
4801 7c51048f Michael Matz
4802 7c51048f Michael Matz
    if (is_tblx) {
4803 7c51048f Michael Matz
        read_vec_element(s, tcg_resl, rd, 0, MO_64);
4804 7c51048f Michael Matz
    } else {
4805 7c51048f Michael Matz
        tcg_gen_movi_i64(tcg_resl, 0);
4806 7c51048f Michael Matz
    }
4807 7c51048f Michael Matz
    if (is_tblx && is_q) {
4808 7c51048f Michael Matz
        read_vec_element(s, tcg_resh, rd, 1, MO_64);
4809 7c51048f Michael Matz
    } else {
4810 7c51048f Michael Matz
        tcg_gen_movi_i64(tcg_resh, 0);
4811 7c51048f Michael Matz
    }
4812 7c51048f Michael Matz
4813 7c51048f Michael Matz
    tcg_idx = tcg_temp_new_i64();
4814 7c51048f Michael Matz
    tcg_regno = tcg_const_i32(rn);
4815 7c51048f Michael Matz
    tcg_numregs = tcg_const_i32(len + 1);
4816 7c51048f Michael Matz
    read_vec_element(s, tcg_idx, rm, 0, MO_64);
4817 7c51048f Michael Matz
    gen_helper_simd_tbl(tcg_resl, cpu_env, tcg_resl, tcg_idx,
4818 7c51048f Michael Matz
                        tcg_regno, tcg_numregs);
4819 7c51048f Michael Matz
    if (is_q) {
4820 7c51048f Michael Matz
        read_vec_element(s, tcg_idx, rm, 1, MO_64);
4821 7c51048f Michael Matz
        gen_helper_simd_tbl(tcg_resh, cpu_env, tcg_resh, tcg_idx,
4822 7c51048f Michael Matz
                            tcg_regno, tcg_numregs);
4823 7c51048f Michael Matz
    }
4824 7c51048f Michael Matz
    tcg_temp_free_i64(tcg_idx);
4825 7c51048f Michael Matz
    tcg_temp_free_i32(tcg_regno);
4826 7c51048f Michael Matz
    tcg_temp_free_i32(tcg_numregs);
4827 7c51048f Michael Matz
4828 7c51048f Michael Matz
    write_vec_element(s, tcg_resl, rd, 0, MO_64);
4829 7c51048f Michael Matz
    tcg_temp_free_i64(tcg_resl);
4830 7c51048f Michael Matz
    write_vec_element(s, tcg_resh, rd, 1, MO_64);
4831 7c51048f Michael Matz
    tcg_temp_free_i64(tcg_resh);
4832 384b26fb Alex Bennée
}
4833 384b26fb Alex Bennée
4834 384b26fb Alex Bennée
/* C3.6.3 ZIP/UZP/TRN
4835 384b26fb Alex Bennée
 *   31  30 29         24 23  22  21 20   16 15 14 12 11 10 9    5 4    0
4836 384b26fb Alex Bennée
 * +---+---+-------------+------+---+------+---+------------------+------+
4837 384b26fb Alex Bennée
 * | 0 | Q | 0 0 1 1 1 0 | size | 0 |  Rm  | 0 | opc | 1 0 |  Rn  |  Rd  |
4838 384b26fb Alex Bennée
 * +---+---+-------------+------+---+------+---+------------------+------+
4839 384b26fb Alex Bennée
 */
4840 384b26fb Alex Bennée
static void disas_simd_zip_trn(DisasContext *s, uint32_t insn)
4841 384b26fb Alex Bennée
{
4842 5fa5469c Michael Matz
    int rd = extract32(insn, 0, 5);
4843 5fa5469c Michael Matz
    int rn = extract32(insn, 5, 5);
4844 5fa5469c Michael Matz
    int rm = extract32(insn, 16, 5);
4845 5fa5469c Michael Matz
    int size = extract32(insn, 22, 2);
4846 5fa5469c Michael Matz
    /* opc field bits [1:0] indicate ZIP/UZP/TRN;
4847 5fa5469c Michael Matz
     * bit 2 indicates 1 vs 2 variant of the insn.
4848 5fa5469c Michael Matz
     */
4849 5fa5469c Michael Matz
    int opcode = extract32(insn, 12, 2);
4850 5fa5469c Michael Matz
    bool part = extract32(insn, 14, 1);
4851 5fa5469c Michael Matz
    bool is_q = extract32(insn, 30, 1);
4852 5fa5469c Michael Matz
    int esize = 8 << size;
4853 5fa5469c Michael Matz
    int i, ofs;
4854 5fa5469c Michael Matz
    int datasize = is_q ? 128 : 64;
4855 5fa5469c Michael Matz
    int elements = datasize / esize;
4856 5fa5469c Michael Matz
    TCGv_i64 tcg_res, tcg_resl, tcg_resh;
4857 5fa5469c Michael Matz
4858 5fa5469c Michael Matz
    if (opcode == 0 || (size == 3 && !is_q)) {
4859 5fa5469c Michael Matz
        unallocated_encoding(s);
4860 5fa5469c Michael Matz
        return;
4861 5fa5469c Michael Matz
    }
4862 5fa5469c Michael Matz
4863 5fa5469c Michael Matz
    tcg_resl = tcg_const_i64(0);
4864 5fa5469c Michael Matz
    tcg_resh = tcg_const_i64(0);
4865 5fa5469c Michael Matz
    tcg_res = tcg_temp_new_i64();
4866 5fa5469c Michael Matz
4867 5fa5469c Michael Matz
    for (i = 0; i < elements; i++) {
4868 5fa5469c Michael Matz
        switch (opcode) {
4869 5fa5469c Michael Matz
        case 1: /* UZP1/2 */
4870 5fa5469c Michael Matz
        {
4871 5fa5469c Michael Matz
            int midpoint = elements / 2;
4872 5fa5469c Michael Matz
            if (i < midpoint) {
4873 5fa5469c Michael Matz
                read_vec_element(s, tcg_res, rn, 2 * i + part, size);
4874 5fa5469c Michael Matz
            } else {
4875 5fa5469c Michael Matz
                read_vec_element(s, tcg_res, rm,
4876 5fa5469c Michael Matz
                                 2 * (i - midpoint) + part, size);
4877 5fa5469c Michael Matz
            }
4878 5fa5469c Michael Matz
            break;
4879 5fa5469c Michael Matz
        }
4880 5fa5469c Michael Matz
        case 2: /* TRN1/2 */
4881 5fa5469c Michael Matz
            if (i & 1) {
4882 5fa5469c Michael Matz
                read_vec_element(s, tcg_res, rm, (i & ~1) + part, size);
4883 5fa5469c Michael Matz
            } else {
4884 5fa5469c Michael Matz
                read_vec_element(s, tcg_res, rn, (i & ~1) + part, size);
4885 5fa5469c Michael Matz
            }
4886 5fa5469c Michael Matz
            break;
4887 5fa5469c Michael Matz
        case 3: /* ZIP1/2 */
4888 5fa5469c Michael Matz
        {
4889 5fa5469c Michael Matz
            int base = part * elements / 2;
4890 5fa5469c Michael Matz
            if (i & 1) {
4891 5fa5469c Michael Matz
                read_vec_element(s, tcg_res, rm, base + (i >> 1), size);
4892 5fa5469c Michael Matz
            } else {
4893 5fa5469c Michael Matz
                read_vec_element(s, tcg_res, rn, base + (i >> 1), size);
4894 5fa5469c Michael Matz
            }
4895 5fa5469c Michael Matz
            break;
4896 5fa5469c Michael Matz
        }
4897 5fa5469c Michael Matz
        default:
4898 5fa5469c Michael Matz
            g_assert_not_reached();
4899 5fa5469c Michael Matz
        }
4900 5fa5469c Michael Matz
4901 5fa5469c Michael Matz
        ofs = i * esize;
4902 5fa5469c Michael Matz
        if (ofs < 64) {
4903 5fa5469c Michael Matz
            tcg_gen_shli_i64(tcg_res, tcg_res, ofs);
4904 5fa5469c Michael Matz
            tcg_gen_or_i64(tcg_resl, tcg_resl, tcg_res);
4905 5fa5469c Michael Matz
        } else {
4906 5fa5469c Michael Matz
            tcg_gen_shli_i64(tcg_res, tcg_res, ofs - 64);
4907 5fa5469c Michael Matz
            tcg_gen_or_i64(tcg_resh, tcg_resh, tcg_res);
4908 5fa5469c Michael Matz
        }
4909 5fa5469c Michael Matz
    }
4910 5fa5469c Michael Matz
4911 5fa5469c Michael Matz
    tcg_temp_free_i64(tcg_res);
4912 5fa5469c Michael Matz
4913 5fa5469c Michael Matz
    write_vec_element(s, tcg_resl, rd, 0, MO_64);
4914 5fa5469c Michael Matz
    tcg_temp_free_i64(tcg_resl);
4915 5fa5469c Michael Matz
    write_vec_element(s, tcg_resh, rd, 1, MO_64);
4916 5fa5469c Michael Matz
    tcg_temp_free_i64(tcg_resh);
4917 384b26fb Alex Bennée
}
4918 384b26fb Alex Bennée
4919 4a0ff1ce Michael Matz
static void do_minmaxop(DisasContext *s, TCGv_i32 tcg_elt1, TCGv_i32 tcg_elt2,
4920 4a0ff1ce Michael Matz
                        int opc, bool is_min, TCGv_ptr fpst)
4921 4a0ff1ce Michael Matz
{
4922 4a0ff1ce Michael Matz
    /* Helper function for disas_simd_across_lanes: do a single precision
4923 4a0ff1ce Michael Matz
     * min/max operation on the specified two inputs,
4924 4a0ff1ce Michael Matz
     * and return the result in tcg_elt1.
4925 4a0ff1ce Michael Matz
     */
4926 4a0ff1ce Michael Matz
    if (opc == 0xc) {
4927 4a0ff1ce Michael Matz
        if (is_min) {
4928 4a0ff1ce Michael Matz
            gen_helper_vfp_minnums(tcg_elt1, tcg_elt1, tcg_elt2, fpst);
4929 4a0ff1ce Michael Matz
        } else {
4930 4a0ff1ce Michael Matz
            gen_helper_vfp_maxnums(tcg_elt1, tcg_elt1, tcg_elt2, fpst);
4931 4a0ff1ce Michael Matz
        }
4932 4a0ff1ce Michael Matz
    } else {
4933 4a0ff1ce Michael Matz
        assert(opc == 0xf);
4934 4a0ff1ce Michael Matz
        if (is_min) {
4935 4a0ff1ce Michael Matz
            gen_helper_vfp_mins(tcg_elt1, tcg_elt1, tcg_elt2, fpst);
4936 4a0ff1ce Michael Matz
        } else {
4937 4a0ff1ce Michael Matz
            gen_helper_vfp_maxs(tcg_elt1, tcg_elt1, tcg_elt2, fpst);
4938 4a0ff1ce Michael Matz
        }
4939 4a0ff1ce Michael Matz
    }
4940 4a0ff1ce Michael Matz
}
4941 4a0ff1ce Michael Matz
4942 384b26fb Alex Bennée
/* C3.6.4 AdvSIMD across lanes
4943 384b26fb Alex Bennée
 *   31  30  29 28       24 23  22 21       17 16    12 11 10 9    5 4    0
4944 384b26fb Alex Bennée
 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
4945 384b26fb Alex Bennée
 * | 0 | Q | U | 0 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 |  Rn  |  Rd  |
4946 384b26fb Alex Bennée
 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
4947 384b26fb Alex Bennée
 */
4948 384b26fb Alex Bennée
static void disas_simd_across_lanes(DisasContext *s, uint32_t insn)
4949 384b26fb Alex Bennée
{
4950 4a0ff1ce Michael Matz
    int rd = extract32(insn, 0, 5);
4951 4a0ff1ce Michael Matz
    int rn = extract32(insn, 5, 5);
4952 4a0ff1ce Michael Matz
    int size = extract32(insn, 22, 2);
4953 4a0ff1ce Michael Matz
    int opcode = extract32(insn, 12, 5);
4954 4a0ff1ce Michael Matz
    bool is_q = extract32(insn, 30, 1);
4955 4a0ff1ce Michael Matz
    bool is_u = extract32(insn, 29, 1);
4956 4a0ff1ce Michael Matz
    bool is_fp = false;
4957 4a0ff1ce Michael Matz
    bool is_min = false;
4958 4a0ff1ce Michael Matz
    int esize;
4959 4a0ff1ce Michael Matz
    int elements;
4960 4a0ff1ce Michael Matz
    int i;
4961 4a0ff1ce Michael Matz
    TCGv_i64 tcg_res, tcg_elt;
4962 4a0ff1ce Michael Matz
4963 4a0ff1ce Michael Matz
    switch (opcode) {
4964 4a0ff1ce Michael Matz
    case 0x1b: /* ADDV */
4965 4a0ff1ce Michael Matz
        if (is_u) {
4966 4a0ff1ce Michael Matz
            unallocated_encoding(s);
4967 4a0ff1ce Michael Matz
            return;
4968 4a0ff1ce Michael Matz
        }
4969 4a0ff1ce Michael Matz
        /* fall through */
4970 4a0ff1ce Michael Matz
    case 0x3: /* SADDLV, UADDLV */
4971 4a0ff1ce Michael Matz
    case 0xa: /* SMAXV, UMAXV */
4972 4a0ff1ce Michael Matz
    case 0x1a: /* SMINV, UMINV */
4973 4a0ff1ce Michael Matz
        if (size == 3 || (size == 2 && !is_q)) {
4974 4a0ff1ce Michael Matz
            unallocated_encoding(s);
4975 4a0ff1ce Michael Matz
            return;
4976 4a0ff1ce Michael Matz
        }
4977 4a0ff1ce Michael Matz
        break;
4978 4a0ff1ce Michael Matz
    case 0xc: /* FMAXNMV, FMINNMV */
4979 4a0ff1ce Michael Matz
    case 0xf: /* FMAXV, FMINV */
4980 4a0ff1ce Michael Matz
        if (!is_u || !is_q || extract32(size, 0, 1)) {
4981 4a0ff1ce Michael Matz
            unallocated_encoding(s);
4982 4a0ff1ce Michael Matz
            return;
4983 4a0ff1ce Michael Matz
        }
4984 4a0ff1ce Michael Matz
        /* Bit 1 of size field encodes min vs max, and actual size is always
4985 4a0ff1ce Michael Matz
         * 32 bits: adjust the size variable so following code can rely on it
4986 4a0ff1ce Michael Matz
         */
4987 4a0ff1ce Michael Matz
        is_min = extract32(size, 1, 1);
4988 4a0ff1ce Michael Matz
        is_fp = true;
4989 4a0ff1ce Michael Matz
        size = 2;
4990 4a0ff1ce Michael Matz
        break;
4991 4a0ff1ce Michael Matz
    default:
4992 4a0ff1ce Michael Matz
        unallocated_encoding(s);
4993 4a0ff1ce Michael Matz
        return;
4994 4a0ff1ce Michael Matz
    }
4995 4a0ff1ce Michael Matz
4996 4a0ff1ce Michael Matz
    esize = 8 << size;
4997 4a0ff1ce Michael Matz
    elements = (is_q ? 128 : 64) / esize;
4998 4a0ff1ce Michael Matz
4999 4a0ff1ce Michael Matz
    tcg_res = tcg_temp_new_i64();
5000 4a0ff1ce Michael Matz
    tcg_elt = tcg_temp_new_i64();
5001 4a0ff1ce Michael Matz
5002 4a0ff1ce Michael Matz
    /* These instructions operate across all lanes of a vector
5003 4a0ff1ce Michael Matz
     * to produce a single result. We can guarantee that a 64
5004 4a0ff1ce Michael Matz
     * bit intermediate is sufficient:
5005 4a0ff1ce Michael Matz
     *  + for [US]ADDLV the maximum element size is 32 bits, and
5006 4a0ff1ce Michael Matz
     *    the result type is 64 bits
5007 4a0ff1ce Michael Matz
     *  + for FMAX*V, FMIN*V, ADDV the intermediate type is the
5008 4a0ff1ce Michael Matz
     *    same as the element size, which is 32 bits at most
5009 4a0ff1ce Michael Matz
     * For the integer operations we can choose to work at 64
5010 4a0ff1ce Michael Matz
     * or 32 bits and truncate at the end; for simplicity
5011 4a0ff1ce Michael Matz
     * we use 64 bits always. The floating point
5012 4a0ff1ce Michael Matz
     * ops do require 32 bit intermediates, though.
5013 4a0ff1ce Michael Matz
     */
5014 4a0ff1ce Michael Matz
    if (!is_fp) {
5015 4a0ff1ce Michael Matz
        read_vec_element(s, tcg_res, rn, 0, size | (is_u ? 0 : MO_SIGN));
5016 4a0ff1ce Michael Matz
5017 4a0ff1ce Michael Matz
        for (i = 1; i < elements; i++) {
5018 4a0ff1ce Michael Matz
            read_vec_element(s, tcg_elt, rn, i, size | (is_u ? 0 : MO_SIGN));
5019 4a0ff1ce Michael Matz
5020 4a0ff1ce Michael Matz
            switch (opcode) {
5021 4a0ff1ce Michael Matz
            case 0x03: /* SADDLV / UADDLV */
5022 4a0ff1ce Michael Matz
            case 0x1b: /* ADDV */
5023 4a0ff1ce Michael Matz
                tcg_gen_add_i64(tcg_res, tcg_res, tcg_elt);
5024 4a0ff1ce Michael Matz
                break;
5025 4a0ff1ce Michael Matz
            case 0x0a: /* SMAXV / UMAXV */
5026 4a0ff1ce Michael Matz
                tcg_gen_movcond_i64(is_u ? TCG_COND_GEU : TCG_COND_GE,
5027 4a0ff1ce Michael Matz
                                    tcg_res,
5028 4a0ff1ce Michael Matz
                                    tcg_res, tcg_elt, tcg_res, tcg_elt);
5029 4a0ff1ce Michael Matz
                break;
5030 4a0ff1ce Michael Matz
            case 0x1a: /* SMINV / UMINV */
5031 4a0ff1ce Michael Matz
                tcg_gen_movcond_i64(is_u ? TCG_COND_LEU : TCG_COND_LE,
5032 4a0ff1ce Michael Matz
                                    tcg_res,
5033 4a0ff1ce Michael Matz
                                    tcg_res, tcg_elt, tcg_res, tcg_elt);
5034 4a0ff1ce Michael Matz
                break;
5035 4a0ff1ce Michael Matz
                break;
5036 4a0ff1ce Michael Matz
            default:
5037 4a0ff1ce Michael Matz
                g_assert_not_reached();
5038 4a0ff1ce Michael Matz
            }
5039 4a0ff1ce Michael Matz
5040 4a0ff1ce Michael Matz
        }
5041 4a0ff1ce Michael Matz
    } else {
5042 4a0ff1ce Michael Matz
        /* Floating point ops which work on 32 bit (single) intermediates.
5043 4a0ff1ce Michael Matz
         * Note that correct NaN propagation requires that we do these
5044 4a0ff1ce Michael Matz
         * operations in exactly the order specified by the pseudocode.
5045 4a0ff1ce Michael Matz
         */
5046 4a0ff1ce Michael Matz
        TCGv_i32 tcg_elt1 = tcg_temp_new_i32();
5047 4a0ff1ce Michael Matz
        TCGv_i32 tcg_elt2 = tcg_temp_new_i32();
5048 4a0ff1ce Michael Matz
        TCGv_i32 tcg_elt3 = tcg_temp_new_i32();
5049 4a0ff1ce Michael Matz
        TCGv_ptr fpst = get_fpstatus_ptr();
5050 4a0ff1ce Michael Matz
5051 4a0ff1ce Michael Matz
        assert(esize == 32);
5052 4a0ff1ce Michael Matz
        assert(elements == 4);
5053 4a0ff1ce Michael Matz
5054 4a0ff1ce Michael Matz
        read_vec_element(s, tcg_elt, rn, 0, MO_32);
5055 4a0ff1ce Michael Matz
        tcg_gen_trunc_i64_i32(tcg_elt1, tcg_elt);
5056 4a0ff1ce Michael Matz
        read_vec_element(s, tcg_elt, rn, 1, MO_32);
5057 4a0ff1ce Michael Matz
        tcg_gen_trunc_i64_i32(tcg_elt2, tcg_elt);
5058 4a0ff1ce Michael Matz
5059 4a0ff1ce Michael Matz
        do_minmaxop(s, tcg_elt1, tcg_elt2, opcode, is_min, fpst);
5060 4a0ff1ce Michael Matz
5061 4a0ff1ce Michael Matz
        read_vec_element(s, tcg_elt, rn, 2, MO_32);
5062 4a0ff1ce Michael Matz
        tcg_gen_trunc_i64_i32(tcg_elt2, tcg_elt);
5063 4a0ff1ce Michael Matz
        read_vec_element(s, tcg_elt, rn, 3, MO_32);
5064 4a0ff1ce Michael Matz
        tcg_gen_trunc_i64_i32(tcg_elt3, tcg_elt);
5065 4a0ff1ce Michael Matz
5066 4a0ff1ce Michael Matz
        do_minmaxop(s, tcg_elt2, tcg_elt3, opcode, is_min, fpst);
5067 4a0ff1ce Michael Matz
5068 4a0ff1ce Michael Matz
        do_minmaxop(s, tcg_elt1, tcg_elt2, opcode, is_min, fpst);
5069 4a0ff1ce Michael Matz
5070 4a0ff1ce Michael Matz
        tcg_gen_extu_i32_i64(tcg_res, tcg_elt1);
5071 4a0ff1ce Michael Matz
        tcg_temp_free_i32(tcg_elt1);
5072 4a0ff1ce Michael Matz
        tcg_temp_free_i32(tcg_elt2);
5073 4a0ff1ce Michael Matz
        tcg_temp_free_i32(tcg_elt3);
5074 4a0ff1ce Michael Matz
        tcg_temp_free_ptr(fpst);
5075 4a0ff1ce Michael Matz
    }
5076 4a0ff1ce Michael Matz
5077 4a0ff1ce Michael Matz
    tcg_temp_free_i64(tcg_elt);
5078 4a0ff1ce Michael Matz
5079 4a0ff1ce Michael Matz
    /* Now truncate the result to the width required for the final output */
5080 4a0ff1ce Michael Matz
    if (opcode == 0x03) {
5081 4a0ff1ce Michael Matz
        /* SADDLV, UADDLV: result is 2*esize */
5082 4a0ff1ce Michael Matz
        size++;
5083 4a0ff1ce Michael Matz
    }
5084 4a0ff1ce Michael Matz
5085 4a0ff1ce Michael Matz
    switch (size) {
5086 4a0ff1ce Michael Matz
    case 0:
5087 4a0ff1ce Michael Matz
        tcg_gen_ext8u_i64(tcg_res, tcg_res);
5088 4a0ff1ce Michael Matz
        break;
5089 4a0ff1ce Michael Matz
    case 1:
5090 4a0ff1ce Michael Matz
        tcg_gen_ext16u_i64(tcg_res, tcg_res);
5091 4a0ff1ce Michael Matz
        break;
5092 4a0ff1ce Michael Matz
    case 2:
5093 4a0ff1ce Michael Matz
        tcg_gen_ext32u_i64(tcg_res, tcg_res);
5094 4a0ff1ce Michael Matz
        break;
5095 4a0ff1ce Michael Matz
    case 3:
5096 4a0ff1ce Michael Matz
        break;
5097 4a0ff1ce Michael Matz
    default:
5098 4a0ff1ce Michael Matz
        g_assert_not_reached();
5099 4a0ff1ce Michael Matz
    }
5100 4a0ff1ce Michael Matz
5101 4a0ff1ce Michael Matz
    write_fp_dreg(s, rd, tcg_res);
5102 4a0ff1ce Michael Matz
    tcg_temp_free_i64(tcg_res);
5103 384b26fb Alex Bennée
}
5104 384b26fb Alex Bennée
5105 67bb9389 Alex Bennée
/* C6.3.31 DUP (Element, Vector)
5106 67bb9389 Alex Bennée
 *
5107 67bb9389 Alex Bennée
 *  31  30   29              21 20    16 15        10  9    5 4    0
5108 67bb9389 Alex Bennée
 * +---+---+-------------------+--------+-------------+------+------+
5109 67bb9389 Alex Bennée
 * | 0 | Q | 0 0 1 1 1 0 0 0 0 |  imm5  | 0 0 0 0 0 1 |  Rn  |  Rd  |
5110 67bb9389 Alex Bennée
 * +---+---+-------------------+--------+-------------+------+------+
5111 67bb9389 Alex Bennée
 *
5112 67bb9389 Alex Bennée
 * size: encoded in imm5 (see ARM ARM LowestSetBit())
5113 67bb9389 Alex Bennée
 */
5114 67bb9389 Alex Bennée
static void handle_simd_dupe(DisasContext *s, int is_q, int rd, int rn,
5115 67bb9389 Alex Bennée
                             int imm5)
5116 67bb9389 Alex Bennée
{
5117 67bb9389 Alex Bennée
    int size = ctz32(imm5);
5118 67bb9389 Alex Bennée
    int esize = 8 << size;
5119 67bb9389 Alex Bennée
    int elements = (is_q ? 128 : 64) / esize;
5120 67bb9389 Alex Bennée
    int index, i;
5121 67bb9389 Alex Bennée
    TCGv_i64 tmp;
5122 67bb9389 Alex Bennée
5123 67bb9389 Alex Bennée
    if (size > 3 || (size == 3 && !is_q)) {
5124 67bb9389 Alex Bennée
        unallocated_encoding(s);
5125 67bb9389 Alex Bennée
        return;
5126 67bb9389 Alex Bennée
    }
5127 67bb9389 Alex Bennée
5128 67bb9389 Alex Bennée
    index = imm5 >> (size + 1);
5129 67bb9389 Alex Bennée
5130 67bb9389 Alex Bennée
    tmp = tcg_temp_new_i64();
5131 67bb9389 Alex Bennée
    read_vec_element(s, tmp, rn, index, size);
5132 67bb9389 Alex Bennée
5133 67bb9389 Alex Bennée
    for (i = 0; i < elements; i++) {
5134 67bb9389 Alex Bennée
        write_vec_element(s, tmp, rd, i, size);
5135 67bb9389 Alex Bennée
    }
5136 67bb9389 Alex Bennée
5137 67bb9389 Alex Bennée
    if (!is_q) {
5138 67bb9389 Alex Bennée
        clear_vec_high(s, rd);
5139 67bb9389 Alex Bennée
    }
5140 67bb9389 Alex Bennée
5141 67bb9389 Alex Bennée
    tcg_temp_free_i64(tmp);
5142 67bb9389 Alex Bennée
}
5143 67bb9389 Alex Bennée
5144 360a6f2d Peter Maydell
/* C6.3.31 DUP (element, scalar)
5145 360a6f2d Peter Maydell
 *  31                   21 20    16 15        10  9    5 4    0
5146 360a6f2d Peter Maydell
 * +-----------------------+--------+-------------+------+------+
5147 360a6f2d Peter Maydell
 * | 0 1 0 1 1 1 1 0 0 0 0 |  imm5  | 0 0 0 0 0 1 |  Rn  |  Rd  |
5148 360a6f2d Peter Maydell
 * +-----------------------+--------+-------------+------+------+
5149 360a6f2d Peter Maydell
 */
5150 360a6f2d Peter Maydell
static void handle_simd_dupes(DisasContext *s, int rd, int rn,
5151 360a6f2d Peter Maydell
                              int imm5)
5152 360a6f2d Peter Maydell
{
5153 360a6f2d Peter Maydell
    int size = ctz32(imm5);
5154 360a6f2d Peter Maydell
    int index;
5155 360a6f2d Peter Maydell
    TCGv_i64 tmp;
5156 360a6f2d Peter Maydell
5157 360a6f2d Peter Maydell
    if (size > 3) {
5158 360a6f2d Peter Maydell
        unallocated_encoding(s);
5159 360a6f2d Peter Maydell
        return;
5160 360a6f2d Peter Maydell
    }
5161 360a6f2d Peter Maydell
5162 360a6f2d Peter Maydell
    index = imm5 >> (size + 1);
5163 360a6f2d Peter Maydell
5164 360a6f2d Peter Maydell
    /* This instruction just extracts the specified element and
5165 360a6f2d Peter Maydell
     * zero-extends it into the bottom of the destination register.
5166 360a6f2d Peter Maydell
     */
5167 360a6f2d Peter Maydell
    tmp = tcg_temp_new_i64();
5168 360a6f2d Peter Maydell
    read_vec_element(s, tmp, rn, index, size);
5169 360a6f2d Peter Maydell
    write_fp_dreg(s, rd, tmp);
5170 360a6f2d Peter Maydell
    tcg_temp_free_i64(tmp);
5171 360a6f2d Peter Maydell
}
5172 360a6f2d Peter Maydell
5173 67bb9389 Alex Bennée
/* C6.3.32 DUP (General)
5174 67bb9389 Alex Bennée
 *
5175 67bb9389 Alex Bennée
 *  31  30   29              21 20    16 15        10  9    5 4    0
5176 67bb9389 Alex Bennée
 * +---+---+-------------------+--------+-------------+------+------+
5177 67bb9389 Alex Bennée
 * | 0 | Q | 0 0 1 1 1 0 0 0 0 |  imm5  | 0 0 0 0 1 1 |  Rn  |  Rd  |
5178 67bb9389 Alex Bennée
 * +---+---+-------------------+--------+-------------+------+------+
5179 67bb9389 Alex Bennée
 *
5180 67bb9389 Alex Bennée
 * size: encoded in imm5 (see ARM ARM LowestSetBit())
5181 67bb9389 Alex Bennée
 */
5182 67bb9389 Alex Bennée
static void handle_simd_dupg(DisasContext *s, int is_q, int rd, int rn,
5183 67bb9389 Alex Bennée
                             int imm5)
5184 67bb9389 Alex Bennée
{
5185 67bb9389 Alex Bennée
    int size = ctz32(imm5);
5186 67bb9389 Alex Bennée
    int esize = 8 << size;
5187 67bb9389 Alex Bennée
    int elements = (is_q ? 128 : 64)/esize;
5188 67bb9389 Alex Bennée
    int i = 0;
5189 67bb9389 Alex Bennée
5190 67bb9389 Alex Bennée
    if (size > 3 || ((size == 3) && !is_q)) {
5191 67bb9389 Alex Bennée
        unallocated_encoding(s);
5192 67bb9389 Alex Bennée
        return;
5193 67bb9389 Alex Bennée
    }
5194 67bb9389 Alex Bennée
    for (i = 0; i < elements; i++) {
5195 67bb9389 Alex Bennée
        write_vec_element(s, cpu_reg(s, rn), rd, i, size);
5196 67bb9389 Alex Bennée
    }
5197 67bb9389 Alex Bennée
    if (!is_q) {
5198 67bb9389 Alex Bennée
        clear_vec_high(s, rd);
5199 67bb9389 Alex Bennée
    }
5200 67bb9389 Alex Bennée
}
5201 67bb9389 Alex Bennée
5202 67bb9389 Alex Bennée
/* C6.3.150 INS (Element)
5203 67bb9389 Alex Bennée
 *
5204 67bb9389 Alex Bennée
 *  31                   21 20    16 15  14    11  10 9    5 4    0
5205 67bb9389 Alex Bennée
 * +-----------------------+--------+------------+---+------+------+
5206 67bb9389 Alex Bennée
 * | 0 1 1 0 1 1 1 0 0 0 0 |  imm5  | 0 |  imm4  | 1 |  Rn  |  Rd  |
5207 67bb9389 Alex Bennée
 * +-----------------------+--------+------------+---+------+------+
5208 67bb9389 Alex Bennée
 *
5209 67bb9389 Alex Bennée
 * size: encoded in imm5 (see ARM ARM LowestSetBit())
5210 67bb9389 Alex Bennée
 * index: encoded in imm5<4:size+1>
5211 67bb9389 Alex Bennée
 */
5212 67bb9389 Alex Bennée
static void handle_simd_inse(DisasContext *s, int rd, int rn,
5213 67bb9389 Alex Bennée
                             int imm4, int imm5)
5214 67bb9389 Alex Bennée
{
5215 67bb9389 Alex Bennée
    int size = ctz32(imm5);
5216 67bb9389 Alex Bennée
    int src_index, dst_index;
5217 67bb9389 Alex Bennée
    TCGv_i64 tmp;
5218 67bb9389 Alex Bennée
5219 67bb9389 Alex Bennée
    if (size > 3) {
5220 67bb9389 Alex Bennée
        unallocated_encoding(s);
5221 67bb9389 Alex Bennée
        return;
5222 67bb9389 Alex Bennée
    }
5223 67bb9389 Alex Bennée
    dst_index = extract32(imm5, 1+size, 5);
5224 67bb9389 Alex Bennée
    src_index = extract32(imm4, size, 4);
5225 67bb9389 Alex Bennée
5226 67bb9389 Alex Bennée
    tmp = tcg_temp_new_i64();
5227 67bb9389 Alex Bennée
5228 67bb9389 Alex Bennée
    read_vec_element(s, tmp, rn, src_index, size);
5229 67bb9389 Alex Bennée
    write_vec_element(s, tmp, rd, dst_index, size);
5230 67bb9389 Alex Bennée
5231 67bb9389 Alex Bennée
    tcg_temp_free_i64(tmp);
5232 67bb9389 Alex Bennée
}
5233 67bb9389 Alex Bennée
5234 67bb9389 Alex Bennée
5235 67bb9389 Alex Bennée
/* C6.3.151 INS (General)
5236 67bb9389 Alex Bennée
 *
5237 67bb9389 Alex Bennée
 *  31                   21 20    16 15        10  9    5 4    0
5238 67bb9389 Alex Bennée
 * +-----------------------+--------+-------------+------+------+
5239 67bb9389 Alex Bennée
 * | 0 1 0 0 1 1 1 0 0 0 0 |  imm5  | 0 0 0 1 1 1 |  Rn  |  Rd  |
5240 67bb9389 Alex Bennée
 * +-----------------------+--------+-------------+------+------+
5241 67bb9389 Alex Bennée
 *
5242 67bb9389 Alex Bennée
 * size: encoded in imm5 (see ARM ARM LowestSetBit())
5243 67bb9389 Alex Bennée
 * index: encoded in imm5<4:size+1>
5244 67bb9389 Alex Bennée
 */
5245 67bb9389 Alex Bennée
static void handle_simd_insg(DisasContext *s, int rd, int rn, int imm5)
5246 67bb9389 Alex Bennée
{
5247 67bb9389 Alex Bennée
    int size = ctz32(imm5);
5248 67bb9389 Alex Bennée
    int idx;
5249 67bb9389 Alex Bennée
5250 67bb9389 Alex Bennée
    if (size > 3) {
5251 67bb9389 Alex Bennée
        unallocated_encoding(s);
5252 67bb9389 Alex Bennée
        return;
5253 67bb9389 Alex Bennée
    }
5254 67bb9389 Alex Bennée
5255 67bb9389 Alex Bennée
    idx = extract32(imm5, 1 + size, 4 - size);
5256 67bb9389 Alex Bennée
    write_vec_element(s, cpu_reg(s, rn), rd, idx, size);
5257 67bb9389 Alex Bennée
}
5258 67bb9389 Alex Bennée
5259 67bb9389 Alex Bennée
/*
5260 67bb9389 Alex Bennée
 * C6.3.321 UMOV (General)
5261 67bb9389 Alex Bennée
 * C6.3.237 SMOV (General)
5262 67bb9389 Alex Bennée
 *
5263 67bb9389 Alex Bennée
 *  31  30   29              21 20    16 15    12   10 9    5 4    0
5264 67bb9389 Alex Bennée
 * +---+---+-------------------+--------+-------------+------+------+
5265 67bb9389 Alex Bennée
 * | 0 | Q | 0 0 1 1 1 0 0 0 0 |  imm5  | 0 0 1 U 1 1 |  Rn  |  Rd  |
5266 67bb9389 Alex Bennée
 * +---+---+-------------------+--------+-------------+------+------+
5267 67bb9389 Alex Bennée
 *
5268 67bb9389 Alex Bennée
 * U: unsigned when set
5269 67bb9389 Alex Bennée
 * size: encoded in imm5 (see ARM ARM LowestSetBit())
5270 67bb9389 Alex Bennée
 */
5271 67bb9389 Alex Bennée
static void handle_simd_umov_smov(DisasContext *s, int is_q, int is_signed,
5272 67bb9389 Alex Bennée
                                  int rn, int rd, int imm5)
5273 67bb9389 Alex Bennée
{
5274 67bb9389 Alex Bennée
    int size = ctz32(imm5);
5275 67bb9389 Alex Bennée
    int element;
5276 67bb9389 Alex Bennée
    TCGv_i64 tcg_rd;
5277 67bb9389 Alex Bennée
5278 67bb9389 Alex Bennée
    /* Check for UnallocatedEncodings */
5279 67bb9389 Alex Bennée
    if (is_signed) {
5280 67bb9389 Alex Bennée
        if (size > 2 || (size == 2 && !is_q)) {
5281 67bb9389 Alex Bennée
            unallocated_encoding(s);
5282 67bb9389 Alex Bennée
            return;
5283 67bb9389 Alex Bennée
        }
5284 67bb9389 Alex Bennée
    } else {
5285 67bb9389 Alex Bennée
        if (size > 3
5286 67bb9389 Alex Bennée
            || (size < 3 && is_q)
5287 67bb9389 Alex Bennée
            || (size == 3 && !is_q)) {
5288 67bb9389 Alex Bennée
            unallocated_encoding(s);
5289 67bb9389 Alex Bennée
            return;
5290 67bb9389 Alex Bennée
        }
5291 67bb9389 Alex Bennée
    }
5292 67bb9389 Alex Bennée
    element = extract32(imm5, 1+size, 4);
5293 67bb9389 Alex Bennée
5294 67bb9389 Alex Bennée
    tcg_rd = cpu_reg(s, rd);
5295 67bb9389 Alex Bennée
    read_vec_element(s, tcg_rd, rn, element, size | (is_signed ? MO_SIGN : 0));
5296 67bb9389 Alex Bennée
    if (is_signed && !is_q) {
5297 67bb9389 Alex Bennée
        tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
5298 67bb9389 Alex Bennée
    }
5299 67bb9389 Alex Bennée
}
5300 67bb9389 Alex Bennée
5301 384b26fb Alex Bennée
/* C3.6.5 AdvSIMD copy
5302 384b26fb Alex Bennée
 *   31  30  29  28             21 20  16 15  14  11 10  9    5 4    0
5303 384b26fb Alex Bennée
 * +---+---+----+-----------------+------+---+------+---+------+------+
5304 384b26fb Alex Bennée
 * | 0 | Q | op | 0 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 |  Rn  |  Rd  |
5305 384b26fb Alex Bennée
 * +---+---+----+-----------------+------+---+------+---+------+------+
5306 384b26fb Alex Bennée
 */
5307 384b26fb Alex Bennée
static void disas_simd_copy(DisasContext *s, uint32_t insn)
5308 384b26fb Alex Bennée
{
5309 67bb9389 Alex Bennée
    int rd = extract32(insn, 0, 5);
5310 67bb9389 Alex Bennée
    int rn = extract32(insn, 5, 5);
5311 67bb9389 Alex Bennée
    int imm4 = extract32(insn, 11, 4);
5312 67bb9389 Alex Bennée
    int op = extract32(insn, 29, 1);
5313 67bb9389 Alex Bennée
    int is_q = extract32(insn, 30, 1);
5314 67bb9389 Alex Bennée
    int imm5 = extract32(insn, 16, 5);
5315 67bb9389 Alex Bennée
5316 67bb9389 Alex Bennée
    if (op) {
5317 67bb9389 Alex Bennée
        if (is_q) {
5318 67bb9389 Alex Bennée
            /* INS (element) */
5319 67bb9389 Alex Bennée
            handle_simd_inse(s, rd, rn, imm4, imm5);
5320 67bb9389 Alex Bennée
        } else {
5321 67bb9389 Alex Bennée
            unallocated_encoding(s);
5322 67bb9389 Alex Bennée
        }
5323 67bb9389 Alex Bennée
    } else {
5324 67bb9389 Alex Bennée
        switch (imm4) {
5325 67bb9389 Alex Bennée
        case 0:
5326 67bb9389 Alex Bennée
            /* DUP (element - vector) */
5327 67bb9389 Alex Bennée
            handle_simd_dupe(s, is_q, rd, rn, imm5);
5328 67bb9389 Alex Bennée
            break;
5329 67bb9389 Alex Bennée
        case 1:
5330 67bb9389 Alex Bennée
            /* DUP (general) */
5331 67bb9389 Alex Bennée
            handle_simd_dupg(s, is_q, rd, rn, imm5);
5332 67bb9389 Alex Bennée
            break;
5333 67bb9389 Alex Bennée
        case 3:
5334 67bb9389 Alex Bennée
            if (is_q) {
5335 67bb9389 Alex Bennée
                /* INS (general) */
5336 67bb9389 Alex Bennée
                handle_simd_insg(s, rd, rn, imm5);
5337 67bb9389 Alex Bennée
            } else {
5338 67bb9389 Alex Bennée
                unallocated_encoding(s);
5339 67bb9389 Alex Bennée
            }
5340 67bb9389 Alex Bennée
            break;
5341 67bb9389 Alex Bennée
        case 5:
5342 67bb9389 Alex Bennée
        case 7:
5343 67bb9389 Alex Bennée
            /* UMOV/SMOV (is_q indicates 32/64; imm4 indicates signedness) */
5344 67bb9389 Alex Bennée
            handle_simd_umov_smov(s, is_q, (imm4 == 5), rn, rd, imm5);
5345 67bb9389 Alex Bennée
            break;
5346 67bb9389 Alex Bennée
        default:
5347 67bb9389 Alex Bennée
            unallocated_encoding(s);
5348 67bb9389 Alex Bennée
            break;
5349 67bb9389 Alex Bennée
        }
5350 67bb9389 Alex Bennée
    }
5351 384b26fb Alex Bennée
}
5352 384b26fb Alex Bennée
5353 384b26fb Alex Bennée
/* C3.6.6 AdvSIMD modified immediate
5354 384b26fb Alex Bennée
 *  31  30   29  28                 19 18 16 15   12  11  10  9     5 4    0
5355 384b26fb Alex Bennée
 * +---+---+----+---------------------+-----+-------+----+---+-------+------+
5356 384b26fb Alex Bennée
 * | 0 | Q | op | 0 1 1 1 1 0 0 0 0 0 | abc | cmode | o2 | 1 | defgh |  Rd  |
5357 384b26fb Alex Bennée
 * +---+---+----+---------------------+-----+-------+----+---+-------+------+
5358 f3f8c4f4 Alex Bennée
 *
5359 f3f8c4f4 Alex Bennée
 * There are a number of operations that can be carried out here:
5360 f3f8c4f4 Alex Bennée
 *   MOVI - move (shifted) imm into register
5361 f3f8c4f4 Alex Bennée
 *   MVNI - move inverted (shifted) imm into register
5362 f3f8c4f4 Alex Bennée
 *   ORR  - bitwise OR of (shifted) imm with register
5363 f3f8c4f4 Alex Bennée
 *   BIC  - bitwise clear of (shifted) imm with register
5364 384b26fb Alex Bennée
 */
5365 384b26fb Alex Bennée
static void disas_simd_mod_imm(DisasContext *s, uint32_t insn)
5366 384b26fb Alex Bennée
{
5367 f3f8c4f4 Alex Bennée
    int rd = extract32(insn, 0, 5);
5368 f3f8c4f4 Alex Bennée
    int cmode = extract32(insn, 12, 4);
5369 f3f8c4f4 Alex Bennée
    int cmode_3_1 = extract32(cmode, 1, 3);
5370 f3f8c4f4 Alex Bennée
    int cmode_0 = extract32(cmode, 0, 1);
5371 f3f8c4f4 Alex Bennée
    int o2 = extract32(insn, 11, 1);
5372 f3f8c4f4 Alex Bennée
    uint64_t abcdefgh = extract32(insn, 5, 5) | (extract32(insn, 16, 3) << 5);
5373 f3f8c4f4 Alex Bennée
    bool is_neg = extract32(insn, 29, 1);
5374 f3f8c4f4 Alex Bennée
    bool is_q = extract32(insn, 30, 1);
5375 f3f8c4f4 Alex Bennée
    uint64_t imm = 0;
5376 f3f8c4f4 Alex Bennée
    TCGv_i64 tcg_rd, tcg_imm;
5377 f3f8c4f4 Alex Bennée
    int i;
5378 f3f8c4f4 Alex Bennée
5379 f3f8c4f4 Alex Bennée
    if (o2 != 0 || ((cmode == 0xf) && is_neg && !is_q)) {
5380 f3f8c4f4 Alex Bennée
        unallocated_encoding(s);
5381 f3f8c4f4 Alex Bennée
        return;
5382 f3f8c4f4 Alex Bennée
    }
5383 f3f8c4f4 Alex Bennée
5384 f3f8c4f4 Alex Bennée
    /* See AdvSIMDExpandImm() in ARM ARM */
5385 f3f8c4f4 Alex Bennée
    switch (cmode_3_1) {
5386 f3f8c4f4 Alex Bennée
    case 0: /* Replicate(Zeros(24):imm8, 2) */
5387 f3f8c4f4 Alex Bennée
    case 1: /* Replicate(Zeros(16):imm8:Zeros(8), 2) */
5388 f3f8c4f4 Alex Bennée
    case 2: /* Replicate(Zeros(8):imm8:Zeros(16), 2) */
5389 f3f8c4f4 Alex Bennée
    case 3: /* Replicate(imm8:Zeros(24), 2) */
5390 f3f8c4f4 Alex Bennée
    {
5391 f3f8c4f4 Alex Bennée
        int shift = cmode_3_1 * 8;
5392 f3f8c4f4 Alex Bennée
        imm = bitfield_replicate(abcdefgh << shift, 32);
5393 f3f8c4f4 Alex Bennée
        break;
5394 f3f8c4f4 Alex Bennée
    }
5395 f3f8c4f4 Alex Bennée
    case 4: /* Replicate(Zeros(8):imm8, 4) */
5396 f3f8c4f4 Alex Bennée
    case 5: /* Replicate(imm8:Zeros(8), 4) */
5397 f3f8c4f4 Alex Bennée
    {
5398 f3f8c4f4 Alex Bennée
        int shift = (cmode_3_1 & 0x1) * 8;
5399 f3f8c4f4 Alex Bennée
        imm = bitfield_replicate(abcdefgh << shift, 16);
5400 f3f8c4f4 Alex Bennée
        break;
5401 f3f8c4f4 Alex Bennée
    }
5402 f3f8c4f4 Alex Bennée
    case 6:
5403 f3f8c4f4 Alex Bennée
        if (cmode_0) {
5404 f3f8c4f4 Alex Bennée
            /* Replicate(Zeros(8):imm8:Ones(16), 2) */
5405 f3f8c4f4 Alex Bennée
            imm = (abcdefgh << 16) | 0xffff;
5406 f3f8c4f4 Alex Bennée
        } else {
5407 f3f8c4f4 Alex Bennée
            /* Replicate(Zeros(16):imm8:Ones(8), 2) */
5408 f3f8c4f4 Alex Bennée
            imm = (abcdefgh << 8) | 0xff;
5409 f3f8c4f4 Alex Bennée
        }
5410 f3f8c4f4 Alex Bennée
        imm = bitfield_replicate(imm, 32);
5411 f3f8c4f4 Alex Bennée
        break;
5412 f3f8c4f4 Alex Bennée
    case 7:
5413 f3f8c4f4 Alex Bennée
        if (!cmode_0 && !is_neg) {
5414 f3f8c4f4 Alex Bennée
            imm = bitfield_replicate(abcdefgh, 8);
5415 f3f8c4f4 Alex Bennée
        } else if (!cmode_0 && is_neg) {
5416 f3f8c4f4 Alex Bennée
            int i;
5417 f3f8c4f4 Alex Bennée
            imm = 0;
5418 f3f8c4f4 Alex Bennée
            for (i = 0; i < 8; i++) {
5419 f3f8c4f4 Alex Bennée
                if ((abcdefgh) & (1 << i)) {
5420 f3f8c4f4 Alex Bennée
                    imm |= 0xffULL << (i * 8);
5421 f3f8c4f4 Alex Bennée
                }
5422 f3f8c4f4 Alex Bennée
            }
5423 f3f8c4f4 Alex Bennée
        } else if (cmode_0) {
5424 f3f8c4f4 Alex Bennée
            if (is_neg) {
5425 f3f8c4f4 Alex Bennée
                imm = (abcdefgh & 0x3f) << 48;
5426 f3f8c4f4 Alex Bennée
                if (abcdefgh & 0x80) {
5427 f3f8c4f4 Alex Bennée
                    imm |= 0x8000000000000000ULL;
5428 f3f8c4f4 Alex Bennée
                }
5429 f3f8c4f4 Alex Bennée
                if (abcdefgh & 0x40) {
5430 f3f8c4f4 Alex Bennée
                    imm |= 0x3fc0000000000000ULL;
5431 f3f8c4f4 Alex Bennée
                } else {
5432 f3f8c4f4 Alex Bennée
                    imm |= 0x4000000000000000ULL;
5433 f3f8c4f4 Alex Bennée
                }
5434 f3f8c4f4 Alex Bennée
            } else {
5435 f3f8c4f4 Alex Bennée
                imm = (abcdefgh & 0x3f) << 19;
5436 f3f8c4f4 Alex Bennée
                if (abcdefgh & 0x80) {
5437 f3f8c4f4 Alex Bennée
                    imm |= 0x80000000;
5438 f3f8c4f4 Alex Bennée
                }
5439 f3f8c4f4 Alex Bennée
                if (abcdefgh & 0x40) {
5440 f3f8c4f4 Alex Bennée
                    imm |= 0x3e000000;
5441 f3f8c4f4 Alex Bennée
                } else {
5442 f3f8c4f4 Alex Bennée
                    imm |= 0x40000000;
5443 f3f8c4f4 Alex Bennée
                }
5444 f3f8c4f4 Alex Bennée
                imm |= (imm << 32);
5445 f3f8c4f4 Alex Bennée
            }
5446 f3f8c4f4 Alex Bennée
        }
5447 f3f8c4f4 Alex Bennée
        break;
5448 f3f8c4f4 Alex Bennée
    }
5449 f3f8c4f4 Alex Bennée
5450 f3f8c4f4 Alex Bennée
    if (cmode_3_1 != 7 && is_neg) {
5451 f3f8c4f4 Alex Bennée
        imm = ~imm;
5452 f3f8c4f4 Alex Bennée
    }
5453 f3f8c4f4 Alex Bennée
5454 f3f8c4f4 Alex Bennée
    tcg_imm = tcg_const_i64(imm);
5455 f3f8c4f4 Alex Bennée
    tcg_rd = new_tmp_a64(s);
5456 f3f8c4f4 Alex Bennée
5457 f3f8c4f4 Alex Bennée
    for (i = 0; i < 2; i++) {
5458 f3f8c4f4 Alex Bennée
        int foffs = i ? fp_reg_hi_offset(rd) : fp_reg_offset(rd, MO_64);
5459 f3f8c4f4 Alex Bennée
5460 f3f8c4f4 Alex Bennée
        if (i == 1 && !is_q) {
5461 f3f8c4f4 Alex Bennée
            /* non-quad ops clear high half of vector */
5462 f3f8c4f4 Alex Bennée
            tcg_gen_movi_i64(tcg_rd, 0);
5463 f3f8c4f4 Alex Bennée
        } else if ((cmode & 0x9) == 0x1 || (cmode & 0xd) == 0x9) {
5464 f3f8c4f4 Alex Bennée
            tcg_gen_ld_i64(tcg_rd, cpu_env, foffs);
5465 f3f8c4f4 Alex Bennée
            if (is_neg) {
5466 f3f8c4f4 Alex Bennée
                /* AND (BIC) */
5467 f3f8c4f4 Alex Bennée
                tcg_gen_and_i64(tcg_rd, tcg_rd, tcg_imm);
5468 f3f8c4f4 Alex Bennée
            } else {
5469 f3f8c4f4 Alex Bennée
                /* ORR */
5470 f3f8c4f4 Alex Bennée
                tcg_gen_or_i64(tcg_rd, tcg_rd, tcg_imm);
5471 f3f8c4f4 Alex Bennée
            }
5472 f3f8c4f4 Alex Bennée
        } else {
5473 f3f8c4f4 Alex Bennée
            /* MOVI */
5474 f3f8c4f4 Alex Bennée
            tcg_gen_mov_i64(tcg_rd, tcg_imm);
5475 f3f8c4f4 Alex Bennée
        }
5476 f3f8c4f4 Alex Bennée
        tcg_gen_st_i64(tcg_rd, cpu_env, foffs);
5477 f3f8c4f4 Alex Bennée
    }
5478 f3f8c4f4 Alex Bennée
5479 f3f8c4f4 Alex Bennée
    tcg_temp_free_i64(tcg_imm);
5480 384b26fb Alex Bennée
}
5481 384b26fb Alex Bennée
5482 384b26fb Alex Bennée
/* C3.6.7 AdvSIMD scalar copy
5483 384b26fb Alex Bennée
 *  31 30  29  28             21 20  16 15  14  11 10  9    5 4    0
5484 384b26fb Alex Bennée
 * +-----+----+-----------------+------+---+------+---+------+------+
5485 384b26fb Alex Bennée
 * | 0 1 | op | 1 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 |  Rn  |  Rd  |
5486 384b26fb Alex Bennée
 * +-----+----+-----------------+------+---+------+---+------+------+
5487 384b26fb Alex Bennée
 */
5488 384b26fb Alex Bennée
static void disas_simd_scalar_copy(DisasContext *s, uint32_t insn)
5489 384b26fb Alex Bennée
{
5490 360a6f2d Peter Maydell
    int rd = extract32(insn, 0, 5);
5491 360a6f2d Peter Maydell
    int rn = extract32(insn, 5, 5);
5492 360a6f2d Peter Maydell
    int imm4 = extract32(insn, 11, 4);
5493 360a6f2d Peter Maydell
    int imm5 = extract32(insn, 16, 5);
5494 360a6f2d Peter Maydell
    int op = extract32(insn, 29, 1);
5495 360a6f2d Peter Maydell
5496 360a6f2d Peter Maydell
    if (op != 0 || imm4 != 0) {
5497 360a6f2d Peter Maydell
        unallocated_encoding(s);
5498 360a6f2d Peter Maydell
        return;
5499 360a6f2d Peter Maydell
    }
5500 360a6f2d Peter Maydell
5501 360a6f2d Peter Maydell
    /* DUP (element, scalar) */
5502 360a6f2d Peter Maydell
    handle_simd_dupes(s, rd, rn, imm5);
5503 384b26fb Alex Bennée
}
5504 384b26fb Alex Bennée
5505 384b26fb Alex Bennée
/* C3.6.8 AdvSIMD scalar pairwise
5506 384b26fb Alex Bennée
 *  31 30  29 28       24 23  22 21       17 16    12 11 10 9    5 4    0
5507 384b26fb Alex Bennée
 * +-----+---+-----------+------+-----------+--------+-----+------+------+
5508 384b26fb Alex Bennée
 * | 0 1 | U | 1 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 |  Rn  |  Rd  |
5509 384b26fb Alex Bennée
 * +-----+---+-----------+------+-----------+--------+-----+------+------+
5510 384b26fb Alex Bennée
 */
5511 384b26fb Alex Bennée
static void disas_simd_scalar_pairwise(DisasContext *s, uint32_t insn)
5512 384b26fb Alex Bennée
{
5513 3720a7ea Peter Maydell
    int u = extract32(insn, 29, 1);
5514 3720a7ea Peter Maydell
    int size = extract32(insn, 22, 2);
5515 3720a7ea Peter Maydell
    int opcode = extract32(insn, 12, 5);
5516 3720a7ea Peter Maydell
    int rn = extract32(insn, 5, 5);
5517 3720a7ea Peter Maydell
    int rd = extract32(insn, 0, 5);
5518 3720a7ea Peter Maydell
    TCGv_ptr fpst;
5519 3720a7ea Peter Maydell
5520 3720a7ea Peter Maydell
    /* For some ops (the FP ones), size[1] is part of the encoding.
5521 3720a7ea Peter Maydell
     * For ADDP strictly it is not but size[1] is always 1 for valid
5522 3720a7ea Peter Maydell
     * encodings.
5523 3720a7ea Peter Maydell
     */
5524 3720a7ea Peter Maydell
    opcode |= (extract32(size, 1, 1) << 5);
5525 3720a7ea Peter Maydell
5526 3720a7ea Peter Maydell
    switch (opcode) {
5527 3720a7ea Peter Maydell
    case 0x3b: /* ADDP */
5528 3720a7ea Peter Maydell
        if (u || size != 3) {
5529 3720a7ea Peter Maydell
            unallocated_encoding(s);
5530 3720a7ea Peter Maydell
            return;
5531 3720a7ea Peter Maydell
        }
5532 3720a7ea Peter Maydell
        TCGV_UNUSED_PTR(fpst);
5533 3720a7ea Peter Maydell
        break;
5534 3720a7ea Peter Maydell
    case 0xc: /* FMAXNMP */
5535 3720a7ea Peter Maydell
    case 0xd: /* FADDP */
5536 3720a7ea Peter Maydell
    case 0xf: /* FMAXP */
5537 3720a7ea Peter Maydell
    case 0x2c: /* FMINNMP */
5538 3720a7ea Peter Maydell
    case 0x2f: /* FMINP */
5539 3720a7ea Peter Maydell
        /* FP op, size[0] is 32 or 64 bit */
5540 3720a7ea Peter Maydell
        if (!u) {
5541 3720a7ea Peter Maydell
            unallocated_encoding(s);
5542 3720a7ea Peter Maydell
            return;
5543 3720a7ea Peter Maydell
        }
5544 3720a7ea Peter Maydell
        size = extract32(size, 0, 1) ? 3 : 2;
5545 3720a7ea Peter Maydell
        fpst = get_fpstatus_ptr();
5546 3720a7ea Peter Maydell
        break;
5547 3720a7ea Peter Maydell
    default:
5548 3720a7ea Peter Maydell
        unallocated_encoding(s);
5549 3720a7ea Peter Maydell
        return;
5550 3720a7ea Peter Maydell
    }
5551 3720a7ea Peter Maydell
5552 3720a7ea Peter Maydell
    if (size == 3) {
5553 3720a7ea Peter Maydell
        TCGv_i64 tcg_op1 = tcg_temp_new_i64();
5554 3720a7ea Peter Maydell
        TCGv_i64 tcg_op2 = tcg_temp_new_i64();
5555 3720a7ea Peter Maydell
        TCGv_i64 tcg_res = tcg_temp_new_i64();
5556 3720a7ea Peter Maydell
5557 3720a7ea Peter Maydell
        read_vec_element(s, tcg_op1, rn, 0, MO_64);
5558 3720a7ea Peter Maydell
        read_vec_element(s, tcg_op2, rn, 1, MO_64);
5559 3720a7ea Peter Maydell
5560 3720a7ea Peter Maydell
        switch (opcode) {
5561 3720a7ea Peter Maydell
        case 0x3b: /* ADDP */
5562 3720a7ea Peter Maydell
            tcg_gen_add_i64(tcg_res, tcg_op1, tcg_op2);
5563 3720a7ea Peter Maydell
            break;
5564 3720a7ea Peter Maydell
        case 0xc: /* FMAXNMP */
5565 3720a7ea Peter Maydell
            gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
5566 3720a7ea Peter Maydell
            break;
5567 3720a7ea Peter Maydell
        case 0xd: /* FADDP */
5568 3720a7ea Peter Maydell
            gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
5569 3720a7ea Peter Maydell
            break;
5570 3720a7ea Peter Maydell
        case 0xf: /* FMAXP */
5571 3720a7ea Peter Maydell
            gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
5572 3720a7ea Peter Maydell
            break;
5573 3720a7ea Peter Maydell
        case 0x2c: /* FMINNMP */
5574 3720a7ea Peter Maydell
            gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
5575 3720a7ea Peter Maydell
            break;
5576 3720a7ea Peter Maydell
        case 0x2f: /* FMINP */
5577 3720a7ea Peter Maydell
            gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
5578 3720a7ea Peter Maydell
            break;
5579 3720a7ea Peter Maydell
        default:
5580 3720a7ea Peter Maydell
            g_assert_not_reached();
5581 3720a7ea Peter Maydell
        }
5582 3720a7ea Peter Maydell
5583 3720a7ea Peter Maydell
        write_fp_dreg(s, rd, tcg_res);
5584 3720a7ea Peter Maydell
5585 3720a7ea Peter Maydell
        tcg_temp_free_i64(tcg_op1);
5586 3720a7ea Peter Maydell
        tcg_temp_free_i64(tcg_op2);
5587 3720a7ea Peter Maydell
        tcg_temp_free_i64(tcg_res);
5588 3720a7ea Peter Maydell
    } else {
5589 3720a7ea Peter Maydell
        TCGv_i32 tcg_op1 = tcg_temp_new_i32();
5590 3720a7ea Peter Maydell
        TCGv_i32 tcg_op2 = tcg_temp_new_i32();
5591 3720a7ea Peter Maydell
        TCGv_i32 tcg_res = tcg_temp_new_i32();
5592 3720a7ea Peter Maydell
5593 3720a7ea Peter Maydell
        read_vec_element_i32(s, tcg_op1, rn, 0, MO_32);
5594 3720a7ea Peter Maydell
        read_vec_element_i32(s, tcg_op2, rn, 1, MO_32);
5595 3720a7ea Peter Maydell
5596 3720a7ea Peter Maydell
        switch (opcode) {
5597 3720a7ea Peter Maydell
        case 0xc: /* FMAXNMP */
5598 3720a7ea Peter Maydell
            gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
5599 3720a7ea Peter Maydell
            break;
5600 3720a7ea Peter Maydell
        case 0xd: /* FADDP */
5601 3720a7ea Peter Maydell
            gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
5602 3720a7ea Peter Maydell
            break;
5603 3720a7ea Peter Maydell
        case 0xf: /* FMAXP */
5604 3720a7ea Peter Maydell
            gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
5605 3720a7ea Peter Maydell
            break;
5606 3720a7ea Peter Maydell
        case 0x2c: /* FMINNMP */
5607 3720a7ea Peter Maydell
            gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
5608 3720a7ea Peter Maydell
            break;
5609 3720a7ea Peter Maydell
        case 0x2f: /* FMINP */
5610 3720a7ea Peter Maydell
            gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
5611 3720a7ea Peter Maydell
            break;
5612 3720a7ea Peter Maydell
        default:
5613 3720a7ea Peter Maydell
            g_assert_not_reached();
5614 3720a7ea Peter Maydell
        }
5615 3720a7ea Peter Maydell
5616 3720a7ea Peter Maydell
        write_fp_sreg(s, rd, tcg_res);
5617 3720a7ea Peter Maydell
5618 3720a7ea Peter Maydell
        tcg_temp_free_i32(tcg_op1);
5619 3720a7ea Peter Maydell
        tcg_temp_free_i32(tcg_op2);
5620 3720a7ea Peter Maydell
        tcg_temp_free_i32(tcg_res);
5621 3720a7ea Peter Maydell
    }
5622 3720a7ea Peter Maydell
5623 3720a7ea Peter Maydell
    if (!TCGV_IS_UNUSED_PTR(fpst)) {
5624 3720a7ea Peter Maydell
        tcg_temp_free_ptr(fpst);
5625 3720a7ea Peter Maydell
    }
5626 384b26fb Alex Bennée
}
5627 384b26fb Alex Bennée
5628 4d1cef84 Alex Bennée
/*
5629 4d1cef84 Alex Bennée
 * Common SSHR[RA]/USHR[RA] - Shift right (optional rounding/accumulate)
5630 4d1cef84 Alex Bennée
 *
5631 4d1cef84 Alex Bennée
 * This code is handles the common shifting code and is used by both
5632 4d1cef84 Alex Bennée
 * the vector and scalar code.
5633 4d1cef84 Alex Bennée
 */
5634 4d1cef84 Alex Bennée
static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src,
5635 4d1cef84 Alex Bennée
                                    TCGv_i64 tcg_rnd, bool accumulate,
5636 4d1cef84 Alex Bennée
                                    bool is_u, int size, int shift)
5637 4d1cef84 Alex Bennée
{
5638 4d1cef84 Alex Bennée
    bool extended_result = false;
5639 4d1cef84 Alex Bennée
    bool round = !TCGV_IS_UNUSED_I64(tcg_rnd);
5640 4d1cef84 Alex Bennée
    int ext_lshift = 0;
5641 4d1cef84 Alex Bennée
    TCGv_i64 tcg_src_hi;
5642 4d1cef84 Alex Bennée
5643 4d1cef84 Alex Bennée
    if (round && size == 3) {
5644 4d1cef84 Alex Bennée
        extended_result = true;
5645 4d1cef84 Alex Bennée
        ext_lshift = 64 - shift;
5646 4d1cef84 Alex Bennée
        tcg_src_hi = tcg_temp_new_i64();
5647 4d1cef84 Alex Bennée
    } else if (shift == 64) {
5648 4d1cef84 Alex Bennée
        if (!accumulate && is_u) {
5649 4d1cef84 Alex Bennée
            /* result is zero */
5650 4d1cef84 Alex Bennée
            tcg_gen_movi_i64(tcg_res, 0);
5651 4d1cef84 Alex Bennée
            return;
5652 4d1cef84 Alex Bennée
        }
5653 4d1cef84 Alex Bennée
    }
5654 4d1cef84 Alex Bennée
5655 4d1cef84 Alex Bennée
    /* Deal with the rounding step */
5656 4d1cef84 Alex Bennée
    if (round) {
5657 4d1cef84 Alex Bennée
        if (extended_result) {
5658 4d1cef84 Alex Bennée
            TCGv_i64 tcg_zero = tcg_const_i64(0);
5659 4d1cef84 Alex Bennée
            if (!is_u) {
5660 4d1cef84 Alex Bennée
                /* take care of sign extending tcg_res */
5661 4d1cef84 Alex Bennée
                tcg_gen_sari_i64(tcg_src_hi, tcg_src, 63);
5662 4d1cef84 Alex Bennée
                tcg_gen_add2_i64(tcg_src, tcg_src_hi,
5663 4d1cef84 Alex Bennée
                                 tcg_src, tcg_src_hi,
5664 4d1cef84 Alex Bennée
                                 tcg_rnd, tcg_zero);
5665 4d1cef84 Alex Bennée
            } else {
5666 4d1cef84 Alex Bennée
                tcg_gen_add2_i64(tcg_src, tcg_src_hi,
5667 4d1cef84 Alex Bennée
                                 tcg_src, tcg_zero,
5668 4d1cef84 Alex Bennée
                                 tcg_rnd, tcg_zero);
5669 4d1cef84 Alex Bennée
            }
5670 4d1cef84 Alex Bennée
            tcg_temp_free_i64(tcg_zero);
5671 4d1cef84 Alex Bennée
        } else {
5672 4d1cef84 Alex Bennée
            tcg_gen_add_i64(tcg_src, tcg_src, tcg_rnd);
5673 4d1cef84 Alex Bennée
        }
5674 4d1cef84 Alex Bennée
    }
5675 4d1cef84 Alex Bennée
5676 4d1cef84 Alex Bennée
    /* Now do the shift right */
5677 4d1cef84 Alex Bennée
    if (round && extended_result) {
5678 4d1cef84 Alex Bennée
        /* extended case, >64 bit precision required */
5679 4d1cef84 Alex Bennée
        if (ext_lshift == 0) {
5680 4d1cef84 Alex Bennée
            /* special case, only high bits matter */
5681 4d1cef84 Alex Bennée
            tcg_gen_mov_i64(tcg_src, tcg_src_hi);
5682 4d1cef84 Alex Bennée
        } else {
5683 4d1cef84 Alex Bennée
            tcg_gen_shri_i64(tcg_src, tcg_src, shift);
5684 4d1cef84 Alex Bennée
            tcg_gen_shli_i64(tcg_src_hi, tcg_src_hi, ext_lshift);
5685 4d1cef84 Alex Bennée
            tcg_gen_or_i64(tcg_src, tcg_src, tcg_src_hi);
5686 4d1cef84 Alex Bennée
        }
5687 4d1cef84 Alex Bennée
    } else {
5688 4d1cef84 Alex Bennée
        if (is_u) {
5689 4d1cef84 Alex Bennée
            if (shift == 64) {
5690 4d1cef84 Alex Bennée
                /* essentially shifting in 64 zeros */
5691 4d1cef84 Alex Bennée
                tcg_gen_movi_i64(tcg_src, 0);
5692 4d1cef84 Alex Bennée
            } else {
5693 4d1cef84 Alex Bennée
                tcg_gen_shri_i64(tcg_src, tcg_src, shift);
5694 4d1cef84 Alex Bennée
            }
5695 4d1cef84 Alex Bennée
        } else {
5696 4d1cef84 Alex Bennée
            if (shift == 64) {
5697 4d1cef84 Alex Bennée
                /* effectively extending the sign-bit */
5698 4d1cef84 Alex Bennée
                tcg_gen_sari_i64(tcg_src, tcg_src, 63);
5699 4d1cef84 Alex Bennée
            } else {
5700 4d1cef84 Alex Bennée
                tcg_gen_sari_i64(tcg_src, tcg_src, shift);
5701 4d1cef84 Alex Bennée
            }
5702 4d1cef84 Alex Bennée
        }
5703 4d1cef84 Alex Bennée
    }
5704 4d1cef84 Alex Bennée
5705 4d1cef84 Alex Bennée
    if (accumulate) {
5706 4d1cef84 Alex Bennée
        tcg_gen_add_i64(tcg_res, tcg_res, tcg_src);
5707 4d1cef84 Alex Bennée
    } else {
5708 4d1cef84 Alex Bennée
        tcg_gen_mov_i64(tcg_res, tcg_src);
5709 4d1cef84 Alex Bennée
    }
5710 4d1cef84 Alex Bennée
5711 4d1cef84 Alex Bennée
    if (extended_result) {
5712 4d1cef84 Alex Bennée
        tcg_temp_free_i64(tcg_src_hi);
5713 4d1cef84 Alex Bennée
    }
5714 4d1cef84 Alex Bennée
}
5715 4d1cef84 Alex Bennée
5716 4d1cef84 Alex Bennée
/* Common SHL/SLI - Shift left with an optional insert */
5717 4d1cef84 Alex Bennée
static void handle_shli_with_ins(TCGv_i64 tcg_res, TCGv_i64 tcg_src,
5718 4d1cef84 Alex Bennée
                                 bool insert, int shift)
5719 4d1cef84 Alex Bennée
{
5720 4d1cef84 Alex Bennée
    if (insert) { /* SLI */
5721 4d1cef84 Alex Bennée
        tcg_gen_deposit_i64(tcg_res, tcg_res, tcg_src, shift, 64 - shift);
5722 4d1cef84 Alex Bennée
    } else { /* SHL */
5723 4d1cef84 Alex Bennée
        tcg_gen_shli_i64(tcg_res, tcg_src, shift);
5724 4d1cef84 Alex Bennée
    }
5725 4d1cef84 Alex Bennée
}
5726 4d1cef84 Alex Bennée
5727 4d1cef84 Alex Bennée
/* SSHR[RA]/USHR[RA] - Scalar shift right (optional rounding/accumulate) */
5728 4d1cef84 Alex Bennée
static void handle_scalar_simd_shri(DisasContext *s,
5729 4d1cef84 Alex Bennée
                                    bool is_u, int immh, int immb,
5730 4d1cef84 Alex Bennée
                                    int opcode, int rn, int rd)
5731 4d1cef84 Alex Bennée
{
5732 4d1cef84 Alex Bennée
    const int size = 3;
5733 4d1cef84 Alex Bennée
    int immhb = immh << 3 | immb;
5734 4d1cef84 Alex Bennée
    int shift = 2 * (8 << size) - immhb;
5735 4d1cef84 Alex Bennée
    bool accumulate = false;
5736 4d1cef84 Alex Bennée
    bool round = false;
5737 4d1cef84 Alex Bennée
    TCGv_i64 tcg_rn;
5738 4d1cef84 Alex Bennée
    TCGv_i64 tcg_rd;
5739 4d1cef84 Alex Bennée
    TCGv_i64 tcg_round;
5740 4d1cef84 Alex Bennée
5741 4d1cef84 Alex Bennée
    if (!extract32(immh, 3, 1)) {
5742 4d1cef84 Alex Bennée
        unallocated_encoding(s);
5743 4d1cef84 Alex Bennée
        return;
5744 4d1cef84 Alex Bennée
    }
5745 4d1cef84 Alex Bennée
5746 4d1cef84 Alex Bennée
    switch (opcode) {
5747 4d1cef84 Alex Bennée
    case 0x02: /* SSRA / USRA (accumulate) */
5748 4d1cef84 Alex Bennée
        accumulate = true;
5749 4d1cef84 Alex Bennée
        break;
5750 4d1cef84 Alex Bennée
    case 0x04: /* SRSHR / URSHR (rounding) */
5751 4d1cef84 Alex Bennée
        round = true;
5752 4d1cef84 Alex Bennée
        break;
5753 4d1cef84 Alex Bennée
    case 0x06: /* SRSRA / URSRA (accum + rounding) */
5754 4d1cef84 Alex Bennée
        accumulate = round = true;
5755 4d1cef84 Alex Bennée
        break;
5756 4d1cef84 Alex Bennée
    }
5757 4d1cef84 Alex Bennée
5758 4d1cef84 Alex Bennée
    if (round) {
5759 4d1cef84 Alex Bennée
        uint64_t round_const = 1ULL << (shift - 1);
5760 4d1cef84 Alex Bennée
        tcg_round = tcg_const_i64(round_const);
5761 4d1cef84 Alex Bennée
    } else {
5762 4d1cef84 Alex Bennée
        TCGV_UNUSED_I64(tcg_round);
5763 4d1cef84 Alex Bennée
    }
5764 4d1cef84 Alex Bennée
5765 4d1cef84 Alex Bennée
    tcg_rn = read_fp_dreg(s, rn);
5766 4d1cef84 Alex Bennée
    tcg_rd = accumulate ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
5767 4d1cef84 Alex Bennée
5768 4d1cef84 Alex Bennée
    handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
5769 4d1cef84 Alex Bennée
                               accumulate, is_u, size, shift);
5770 4d1cef84 Alex Bennée
5771 4d1cef84 Alex Bennée
    write_fp_dreg(s, rd, tcg_rd);
5772 4d1cef84 Alex Bennée
5773 4d1cef84 Alex Bennée
    tcg_temp_free_i64(tcg_rn);
5774 4d1cef84 Alex Bennée
    tcg_temp_free_i64(tcg_rd);
5775 4d1cef84 Alex Bennée
    if (round) {
5776 4d1cef84 Alex Bennée
        tcg_temp_free_i64(tcg_round);
5777 4d1cef84 Alex Bennée
    }
5778 4d1cef84 Alex Bennée
}
5779 4d1cef84 Alex Bennée
5780 4d1cef84 Alex Bennée
/* SHL/SLI - Scalar shift left */
5781 4d1cef84 Alex Bennée
static void handle_scalar_simd_shli(DisasContext *s, bool insert,
5782 4d1cef84 Alex Bennée
                                    int immh, int immb, int opcode,
5783 4d1cef84 Alex Bennée
                                    int rn, int rd)
5784 4d1cef84 Alex Bennée
{
5785 4d1cef84 Alex Bennée
    int size = 32 - clz32(immh) - 1;
5786 4d1cef84 Alex Bennée
    int immhb = immh << 3 | immb;
5787 4d1cef84 Alex Bennée
    int shift = immhb - (8 << size);
5788 4d1cef84 Alex Bennée
    TCGv_i64 tcg_rn = new_tmp_a64(s);
5789 4d1cef84 Alex Bennée
    TCGv_i64 tcg_rd = new_tmp_a64(s);
5790 4d1cef84 Alex Bennée
5791 4d1cef84 Alex Bennée
    if (!extract32(immh, 3, 1)) {
5792 4d1cef84 Alex Bennée
        unallocated_encoding(s);
5793 4d1cef84 Alex Bennée
        return;
5794 4d1cef84 Alex Bennée
    }
5795 4d1cef84 Alex Bennée
5796 4d1cef84 Alex Bennée
    tcg_rn = read_fp_dreg(s, rn);
5797 4d1cef84 Alex Bennée
    tcg_rd = insert ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
5798 4d1cef84 Alex Bennée
5799 4d1cef84 Alex Bennée
    handle_shli_with_ins(tcg_rd, tcg_rn, insert, shift);
5800 4d1cef84 Alex Bennée
5801 4d1cef84 Alex Bennée
    write_fp_dreg(s, rd, tcg_rd);
5802 4d1cef84 Alex Bennée
5803 4d1cef84 Alex Bennée
    tcg_temp_free_i64(tcg_rn);
5804 4d1cef84 Alex Bennée
    tcg_temp_free_i64(tcg_rd);
5805 4d1cef84 Alex Bennée
}
5806 4d1cef84 Alex Bennée
5807 384b26fb Alex Bennée
/* C3.6.9 AdvSIMD scalar shift by immediate
5808 384b26fb Alex Bennée
 *  31 30  29 28         23 22  19 18  16 15    11  10 9    5 4    0
5809 384b26fb Alex Bennée
 * +-----+---+-------------+------+------+--------+---+------+------+
5810 384b26fb Alex Bennée
 * | 0 1 | U | 1 1 1 1 1 0 | immh | immb | opcode | 1 |  Rn  |  Rd  |
5811 384b26fb Alex Bennée
 * +-----+---+-------------+------+------+--------+---+------+------+
5812 4d1cef84 Alex Bennée
 *
5813 4d1cef84 Alex Bennée
 * This is the scalar version so it works on a fixed sized registers
5814 384b26fb Alex Bennée
 */
5815 384b26fb Alex Bennée
static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn)
5816 384b26fb Alex Bennée
{
5817 4d1cef84 Alex Bennée
    int rd = extract32(insn, 0, 5);
5818 4d1cef84 Alex Bennée
    int rn = extract32(insn, 5, 5);
5819 4d1cef84 Alex Bennée
    int opcode = extract32(insn, 11, 5);
5820 4d1cef84 Alex Bennée
    int immb = extract32(insn, 16, 3);
5821 4d1cef84 Alex Bennée
    int immh = extract32(insn, 19, 4);
5822 4d1cef84 Alex Bennée
    bool is_u = extract32(insn, 29, 1);
5823 4d1cef84 Alex Bennée
5824 4d1cef84 Alex Bennée
    switch (opcode) {
5825 4d1cef84 Alex Bennée
    case 0x00: /* SSHR / USHR */
5826 4d1cef84 Alex Bennée
    case 0x02: /* SSRA / USRA */
5827 4d1cef84 Alex Bennée
    case 0x04: /* SRSHR / URSHR */
5828 4d1cef84 Alex Bennée
    case 0x06: /* SRSRA / URSRA */
5829 4d1cef84 Alex Bennée
        handle_scalar_simd_shri(s, is_u, immh, immb, opcode, rn, rd);
5830 4d1cef84 Alex Bennée
        break;
5831 4d1cef84 Alex Bennée
    case 0x0a: /* SHL / SLI */
5832 4d1cef84 Alex Bennée
        handle_scalar_simd_shli(s, is_u, immh, immb, opcode, rn, rd);
5833 4d1cef84 Alex Bennée
        break;
5834 4d1cef84 Alex Bennée
    default:
5835 4d1cef84 Alex Bennée
        unsupported_encoding(s, insn);
5836 4d1cef84 Alex Bennée
        break;
5837 4d1cef84 Alex Bennée
    }
5838 384b26fb Alex Bennée
}
5839 384b26fb Alex Bennée
5840 384b26fb Alex Bennée
/* C3.6.10 AdvSIMD scalar three different
5841 384b26fb Alex Bennée
 *  31 30  29 28       24 23  22  21 20  16 15    12 11 10 9    5 4    0
5842 384b26fb Alex Bennée
 * +-----+---+-----------+------+---+------+--------+-----+------+------+
5843 384b26fb Alex Bennée
 * | 0 1 | U | 1 1 1 1 0 | size | 1 |  Rm  | opcode | 0 0 |  Rn  |  Rd  |
5844 384b26fb Alex Bennée
 * +-----+---+-----------+------+---+------+--------+-----+------+------+
5845 384b26fb Alex Bennée
 */
5846 384b26fb Alex Bennée
static void disas_simd_scalar_three_reg_diff(DisasContext *s, uint32_t insn)
5847 384b26fb Alex Bennée
{
5848 b033cd3d Peter Maydell
    bool is_u = extract32(insn, 29, 1);
5849 b033cd3d Peter Maydell
    int size = extract32(insn, 22, 2);
5850 b033cd3d Peter Maydell
    int opcode = extract32(insn, 12, 4);
5851 b033cd3d Peter Maydell
    int rm = extract32(insn, 16, 5);
5852 b033cd3d Peter Maydell
    int rn = extract32(insn, 5, 5);
5853 b033cd3d Peter Maydell
    int rd = extract32(insn, 0, 5);
5854 b033cd3d Peter Maydell
5855 b033cd3d Peter Maydell
    if (is_u) {
5856 b033cd3d Peter Maydell
        unallocated_encoding(s);
5857 b033cd3d Peter Maydell
        return;
5858 b033cd3d Peter Maydell
    }
5859 b033cd3d Peter Maydell
5860 b033cd3d Peter Maydell
    switch (opcode) {
5861 b033cd3d Peter Maydell
    case 0x9: /* SQDMLAL, SQDMLAL2 */
5862 b033cd3d Peter Maydell
    case 0xb: /* SQDMLSL, SQDMLSL2 */
5863 b033cd3d Peter Maydell
    case 0xd: /* SQDMULL, SQDMULL2 */
5864 b033cd3d Peter Maydell
        if (size == 0 || size == 3) {
5865 b033cd3d Peter Maydell
            unallocated_encoding(s);
5866 b033cd3d Peter Maydell
            return;
5867 b033cd3d Peter Maydell
        }
5868 b033cd3d Peter Maydell
        break;
5869 b033cd3d Peter Maydell
    default:
5870 b033cd3d Peter Maydell
        unallocated_encoding(s);
5871 b033cd3d Peter Maydell
        return;
5872 b033cd3d Peter Maydell
    }
5873 b033cd3d Peter Maydell
5874 b033cd3d Peter Maydell
    if (size == 2) {
5875 b033cd3d Peter Maydell
        TCGv_i64 tcg_op1 = tcg_temp_new_i64();
5876 b033cd3d Peter Maydell
        TCGv_i64 tcg_op2 = tcg_temp_new_i64();
5877 b033cd3d Peter Maydell
        TCGv_i64 tcg_res = tcg_temp_new_i64();
5878 b033cd3d Peter Maydell
5879 b033cd3d Peter Maydell
        read_vec_element(s, tcg_op1, rn, 0, MO_32 | MO_SIGN);
5880 b033cd3d Peter Maydell
        read_vec_element(s, tcg_op2, rm, 0, MO_32 | MO_SIGN);
5881 b033cd3d Peter Maydell
5882 b033cd3d Peter Maydell
        tcg_gen_mul_i64(tcg_res, tcg_op1, tcg_op2);
5883 b033cd3d Peter Maydell
        gen_helper_neon_addl_saturate_s64(tcg_res, cpu_env, tcg_res, tcg_res);
5884 b033cd3d Peter Maydell
5885 b033cd3d Peter Maydell
        switch (opcode) {
5886 b033cd3d Peter Maydell
        case 0xd: /* SQDMULL, SQDMULL2 */
5887 b033cd3d Peter Maydell
            break;
5888 b033cd3d Peter Maydell
        case 0xb: /* SQDMLSL, SQDMLSL2 */
5889 b033cd3d Peter Maydell
            tcg_gen_neg_i64(tcg_res, tcg_res);
5890 b033cd3d Peter Maydell
            /* fall through */
5891 b033cd3d Peter Maydell
        case 0x9: /* SQDMLAL, SQDMLAL2 */
5892 b033cd3d Peter Maydell
            read_vec_element(s, tcg_op1, rd, 0, MO_64);
5893 b033cd3d Peter Maydell
            gen_helper_neon_addl_saturate_s64(tcg_res, cpu_env,
5894 b033cd3d Peter Maydell
                                              tcg_res, tcg_op1);
5895 b033cd3d Peter Maydell
            break;
5896 b033cd3d Peter Maydell
        default:
5897 b033cd3d Peter Maydell
            g_assert_not_reached();
5898 b033cd3d Peter Maydell
        }
5899 b033cd3d Peter Maydell
5900 b033cd3d Peter Maydell
        write_fp_dreg(s, rd, tcg_res);
5901 b033cd3d Peter Maydell
5902 b033cd3d Peter Maydell
        tcg_temp_free_i64(tcg_op1);
5903 b033cd3d Peter Maydell
        tcg_temp_free_i64(tcg_op2);
5904 b033cd3d Peter Maydell
        tcg_temp_free_i64(tcg_res);
5905 b033cd3d Peter Maydell
    } else {
5906 b033cd3d Peter Maydell
        TCGv_i32 tcg_op1 = tcg_temp_new_i32();
5907 b033cd3d Peter Maydell
        TCGv_i32 tcg_op2 = tcg_temp_new_i32();
5908 b033cd3d Peter Maydell
        TCGv_i64 tcg_res = tcg_temp_new_i64();
5909 b033cd3d Peter Maydell
5910 b033cd3d Peter Maydell
        read_vec_element_i32(s, tcg_op1, rn, 0, MO_16);
5911 b033cd3d Peter Maydell
        read_vec_element_i32(s, tcg_op2, rm, 0, MO_16);
5912 b033cd3d Peter Maydell
5913 b033cd3d Peter Maydell
        gen_helper_neon_mull_s16(tcg_res, tcg_op1, tcg_op2);
5914 b033cd3d Peter Maydell
        gen_helper_neon_addl_saturate_s32(tcg_res, cpu_env, tcg_res, tcg_res);
5915 b033cd3d Peter Maydell
5916 b033cd3d Peter Maydell
        switch (opcode) {
5917 b033cd3d Peter Maydell
        case 0xd: /* SQDMULL, SQDMULL2 */
5918 b033cd3d Peter Maydell
            break;
5919 b033cd3d Peter Maydell
        case 0xb: /* SQDMLSL, SQDMLSL2 */
5920 b033cd3d Peter Maydell
            gen_helper_neon_negl_u32(tcg_res, tcg_res);
5921 b033cd3d Peter Maydell
            /* fall through */
5922 b033cd3d Peter Maydell
        case 0x9: /* SQDMLAL, SQDMLAL2 */
5923 b033cd3d Peter Maydell
        {
5924 b033cd3d Peter Maydell
            TCGv_i64 tcg_op3 = tcg_temp_new_i64();
5925 b033cd3d Peter Maydell
            read_vec_element(s, tcg_op3, rd, 0, MO_32);
5926 b033cd3d Peter Maydell
            gen_helper_neon_addl_saturate_s32(tcg_res, cpu_env,
5927 b033cd3d Peter Maydell
                                              tcg_res, tcg_op3);
5928 b033cd3d Peter Maydell
            tcg_temp_free_i64(tcg_op3);
5929 b033cd3d Peter Maydell
            break;
5930 b033cd3d Peter Maydell
        }
5931 b033cd3d Peter Maydell
        default:
5932 b033cd3d Peter Maydell
            g_assert_not_reached();
5933 b033cd3d Peter Maydell
        }
5934 b033cd3d Peter Maydell
5935 b033cd3d Peter Maydell
        tcg_gen_ext32u_i64(tcg_res, tcg_res);
5936 b033cd3d Peter Maydell
        write_fp_dreg(s, rd, tcg_res);
5937 b033cd3d Peter Maydell
5938 b033cd3d Peter Maydell
        tcg_temp_free_i32(tcg_op1);
5939 b033cd3d Peter Maydell
        tcg_temp_free_i32(tcg_op2);
5940 b033cd3d Peter Maydell
        tcg_temp_free_i64(tcg_res);
5941 b033cd3d Peter Maydell
    }
5942 384b26fb Alex Bennée
}
5943 384b26fb Alex Bennée
5944 b305dba6 Peter Maydell
static void handle_3same_64(DisasContext *s, int opcode, bool u,
5945 b305dba6 Peter Maydell
                            TCGv_i64 tcg_rd, TCGv_i64 tcg_rn, TCGv_i64 tcg_rm)
5946 b305dba6 Peter Maydell
{
5947 b305dba6 Peter Maydell
    /* Handle 64x64->64 opcodes which are shared between the scalar
5948 b305dba6 Peter Maydell
     * and vector 3-same groups. We cover every opcode where size == 3
5949 b305dba6 Peter Maydell
     * is valid in either the three-reg-same (integer, not pairwise)
5950 b305dba6 Peter Maydell
     * or scalar-three-reg-same groups. (Some opcodes are not yet
5951 b305dba6 Peter Maydell
     * implemented.)
5952 b305dba6 Peter Maydell
     */
5953 b305dba6 Peter Maydell
    TCGCond cond;
5954 b305dba6 Peter Maydell
5955 b305dba6 Peter Maydell
    switch (opcode) {
5956 6d9571f7 Peter Maydell
    case 0x1: /* SQADD */
5957 6d9571f7 Peter Maydell
        if (u) {
5958 6d9571f7 Peter Maydell
            gen_helper_neon_qadd_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
5959 6d9571f7 Peter Maydell
        } else {
5960 6d9571f7 Peter Maydell
            gen_helper_neon_qadd_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
5961 6d9571f7 Peter Maydell
        }
5962 6d9571f7 Peter Maydell
        break;
5963 6d9571f7 Peter Maydell
    case 0x5: /* SQSUB */
5964 6d9571f7 Peter Maydell
        if (u) {
5965 6d9571f7 Peter Maydell
            gen_helper_neon_qsub_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
5966 6d9571f7 Peter Maydell
        } else {
5967 6d9571f7 Peter Maydell
            gen_helper_neon_qsub_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
5968 6d9571f7 Peter Maydell
        }
5969 6d9571f7 Peter Maydell
        break;
5970 b305dba6 Peter Maydell
    case 0x6: /* CMGT, CMHI */
5971 b305dba6 Peter Maydell
        /* 64 bit integer comparison, result = test ? (2^64 - 1) : 0.
5972 b305dba6 Peter Maydell
         * We implement this using setcond (test) and then negating.
5973 b305dba6 Peter Maydell
         */
5974 b305dba6 Peter Maydell
        cond = u ? TCG_COND_GTU : TCG_COND_GT;
5975 b305dba6 Peter Maydell
    do_cmop:
5976 b305dba6 Peter Maydell
        tcg_gen_setcond_i64(cond, tcg_rd, tcg_rn, tcg_rm);
5977 b305dba6 Peter Maydell
        tcg_gen_neg_i64(tcg_rd, tcg_rd);
5978 b305dba6 Peter Maydell
        break;
5979 b305dba6 Peter Maydell
    case 0x7: /* CMGE, CMHS */
5980 b305dba6 Peter Maydell
        cond = u ? TCG_COND_GEU : TCG_COND_GE;
5981 b305dba6 Peter Maydell
        goto do_cmop;
5982 b305dba6 Peter Maydell
    case 0x11: /* CMTST, CMEQ */
5983 b305dba6 Peter Maydell
        if (u) {
5984 b305dba6 Peter Maydell
            cond = TCG_COND_EQ;
5985 b305dba6 Peter Maydell
            goto do_cmop;
5986 b305dba6 Peter Maydell
        }
5987 b305dba6 Peter Maydell
        /* CMTST : test is "if (X & Y != 0)". */
5988 b305dba6 Peter Maydell
        tcg_gen_and_i64(tcg_rd, tcg_rn, tcg_rm);
5989 b305dba6 Peter Maydell
        tcg_gen_setcondi_i64(TCG_COND_NE, tcg_rd, tcg_rd, 0);
5990 b305dba6 Peter Maydell
        tcg_gen_neg_i64(tcg_rd, tcg_rd);
5991 b305dba6 Peter Maydell
        break;
5992 6d9571f7 Peter Maydell
    case 0x8: /* SSHL, USHL */
5993 b305dba6 Peter Maydell
        if (u) {
5994 6d9571f7 Peter Maydell
            gen_helper_neon_shl_u64(tcg_rd, tcg_rn, tcg_rm);
5995 b305dba6 Peter Maydell
        } else {
5996 6d9571f7 Peter Maydell
            gen_helper_neon_shl_s64(tcg_rd, tcg_rn, tcg_rm);
5997 b305dba6 Peter Maydell
        }
5998 b305dba6 Peter Maydell
        break;
5999 b305dba6 Peter Maydell
    case 0x9: /* SQSHL, UQSHL */
6000 6d9571f7 Peter Maydell
        if (u) {
6001 6d9571f7 Peter Maydell
            gen_helper_neon_qshl_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6002 6d9571f7 Peter Maydell
        } else {
6003 6d9571f7 Peter Maydell
            gen_helper_neon_qshl_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6004 6d9571f7 Peter Maydell
        }
6005 6d9571f7 Peter Maydell
        break;
6006 b305dba6 Peter Maydell
    case 0xa: /* SRSHL, URSHL */
6007 6d9571f7 Peter Maydell
        if (u) {
6008 6d9571f7 Peter Maydell
            gen_helper_neon_rshl_u64(tcg_rd, tcg_rn, tcg_rm);
6009 6d9571f7 Peter Maydell
        } else {
6010 6d9571f7 Peter Maydell
            gen_helper_neon_rshl_s64(tcg_rd, tcg_rn, tcg_rm);
6011 6d9571f7 Peter Maydell
        }
6012 6d9571f7 Peter Maydell
        break;
6013 b305dba6 Peter Maydell
    case 0xb: /* SQRSHL, UQRSHL */
6014 6d9571f7 Peter Maydell
        if (u) {
6015 6d9571f7 Peter Maydell
            gen_helper_neon_qrshl_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6016 6d9571f7 Peter Maydell
        } else {
6017 6d9571f7 Peter Maydell
            gen_helper_neon_qrshl_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
6018 6d9571f7 Peter Maydell
        }
6019 6d9571f7 Peter Maydell
        break;
6020 6d9571f7 Peter Maydell
    case 0x10: /* ADD, SUB */
6021 6d9571f7 Peter Maydell
        if (u) {
6022 6d9571f7 Peter Maydell
            tcg_gen_sub_i64(tcg_rd, tcg_rn, tcg_rm);
6023 6d9571f7 Peter Maydell
        } else {
6024 6d9571f7 Peter Maydell
            tcg_gen_add_i64(tcg_rd, tcg_rn, tcg_rm);
6025 6d9571f7 Peter Maydell
        }
6026 6d9571f7 Peter Maydell
        break;
6027 b305dba6 Peter Maydell
    default:
6028 b305dba6 Peter Maydell
        g_assert_not_reached();
6029 b305dba6 Peter Maydell
    }
6030 b305dba6 Peter Maydell
}
6031 b305dba6 Peter Maydell
6032 845ea09a Peter Maydell
/* Handle the 3-same-operands float operations; shared by the scalar
6033 845ea09a Peter Maydell
 * and vector encodings. The caller must filter out any encodings
6034 845ea09a Peter Maydell
 * not allocated for the encoding it is dealing with.
6035 845ea09a Peter Maydell
 */
6036 845ea09a Peter Maydell
static void handle_3same_float(DisasContext *s, int size, int elements,
6037 845ea09a Peter Maydell
                               int fpopcode, int rd, int rn, int rm)
6038 845ea09a Peter Maydell
{
6039 845ea09a Peter Maydell
    int pass;
6040 845ea09a Peter Maydell
    TCGv_ptr fpst = get_fpstatus_ptr();
6041 845ea09a Peter Maydell
6042 845ea09a Peter Maydell
    for (pass = 0; pass < elements; pass++) {
6043 845ea09a Peter Maydell
        if (size) {
6044 845ea09a Peter Maydell
            /* Double */
6045 845ea09a Peter Maydell
            TCGv_i64 tcg_op1 = tcg_temp_new_i64();
6046 845ea09a Peter Maydell
            TCGv_i64 tcg_op2 = tcg_temp_new_i64();
6047 845ea09a Peter Maydell
            TCGv_i64 tcg_res = tcg_temp_new_i64();
6048 845ea09a Peter Maydell
6049 845ea09a Peter Maydell
            read_vec_element(s, tcg_op1, rn, pass, MO_64);
6050 845ea09a Peter Maydell
            read_vec_element(s, tcg_op2, rm, pass, MO_64);
6051 845ea09a Peter Maydell
6052 845ea09a Peter Maydell
            switch (fpopcode) {
6053 057d5f62 Peter Maydell
            case 0x39: /* FMLS */
6054 057d5f62 Peter Maydell
                /* As usual for ARM, separate negation for fused multiply-add */
6055 057d5f62 Peter Maydell
                gen_helper_vfp_negd(tcg_op1, tcg_op1);
6056 057d5f62 Peter Maydell
                /* fall through */
6057 057d5f62 Peter Maydell
            case 0x19: /* FMLA */
6058 057d5f62 Peter Maydell
                read_vec_element(s, tcg_res, rd, pass, MO_64);
6059 057d5f62 Peter Maydell
                gen_helper_vfp_muladdd(tcg_res, tcg_op1, tcg_op2,
6060 057d5f62 Peter Maydell
                                       tcg_res, fpst);
6061 057d5f62 Peter Maydell
                break;
6062 845ea09a Peter Maydell
            case 0x18: /* FMAXNM */
6063 845ea09a Peter Maydell
                gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
6064 845ea09a Peter Maydell
                break;
6065 845ea09a Peter Maydell
            case 0x1a: /* FADD */
6066 845ea09a Peter Maydell
                gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
6067 845ea09a Peter Maydell
                break;
6068 057d5f62 Peter Maydell
            case 0x1b: /* FMULX */
6069 057d5f62 Peter Maydell
                gen_helper_vfp_mulxd(tcg_res, tcg_op1, tcg_op2, fpst);
6070 057d5f62 Peter Maydell
                break;
6071 8908f4d1 Alex Bennée
            case 0x1c: /* FCMEQ */
6072 8908f4d1 Alex Bennée
                gen_helper_neon_ceq_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6073 8908f4d1 Alex Bennée
                break;
6074 845ea09a Peter Maydell
            case 0x1e: /* FMAX */
6075 845ea09a Peter Maydell
                gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
6076 845ea09a Peter Maydell
                break;
6077 057d5f62 Peter Maydell
            case 0x1f: /* FRECPS */
6078 057d5f62 Peter Maydell
                gen_helper_recpsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6079 057d5f62 Peter Maydell
                break;
6080 845ea09a Peter Maydell
            case 0x38: /* FMINNM */
6081 845ea09a Peter Maydell
                gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
6082 845ea09a Peter Maydell
                break;
6083 845ea09a Peter Maydell
            case 0x3a: /* FSUB */
6084 845ea09a Peter Maydell
                gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
6085 845ea09a Peter Maydell
                break;
6086 845ea09a Peter Maydell
            case 0x3e: /* FMIN */
6087 845ea09a Peter Maydell
                gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
6088 845ea09a Peter Maydell
                break;
6089 057d5f62 Peter Maydell
            case 0x3f: /* FRSQRTS */
6090 057d5f62 Peter Maydell
                gen_helper_rsqrtsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6091 057d5f62 Peter Maydell
                break;
6092 845ea09a Peter Maydell
            case 0x5b: /* FMUL */
6093 845ea09a Peter Maydell
                gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
6094 845ea09a Peter Maydell
                break;
6095 8908f4d1 Alex Bennée
            case 0x5c: /* FCMGE */
6096 8908f4d1 Alex Bennée
                gen_helper_neon_cge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6097 8908f4d1 Alex Bennée
                break;
6098 057d5f62 Peter Maydell
            case 0x5d: /* FACGE */
6099 057d5f62 Peter Maydell
                gen_helper_neon_acge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6100 057d5f62 Peter Maydell
                break;
6101 845ea09a Peter Maydell
            case 0x5f: /* FDIV */
6102 845ea09a Peter Maydell
                gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst);
6103 845ea09a Peter Maydell
                break;
6104 845ea09a Peter Maydell
            case 0x7a: /* FABD */
6105 845ea09a Peter Maydell
                gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
6106 845ea09a Peter Maydell
                gen_helper_vfp_absd(tcg_res, tcg_res);
6107 845ea09a Peter Maydell
                break;
6108 8908f4d1 Alex Bennée
            case 0x7c: /* FCMGT */
6109 8908f4d1 Alex Bennée
                gen_helper_neon_cgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6110 8908f4d1 Alex Bennée
                break;
6111 057d5f62 Peter Maydell
            case 0x7d: /* FACGT */
6112 057d5f62 Peter Maydell
                gen_helper_neon_acgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
6113 057d5f62 Peter Maydell
                break;
6114 845ea09a Peter Maydell
            default:
6115 845ea09a Peter Maydell
                g_assert_not_reached();
6116 845ea09a Peter Maydell
            }
6117 845ea09a Peter Maydell
6118 845ea09a Peter Maydell
            write_vec_element(s, tcg_res, rd, pass, MO_64);
6119 845ea09a Peter Maydell
6120 845ea09a Peter Maydell
            tcg_temp_free_i64(tcg_res);
6121 845ea09a Peter Maydell
            tcg_temp_free_i64(tcg_op1);
6122 845ea09a Peter Maydell
            tcg_temp_free_i64(tcg_op2);
6123 845ea09a Peter Maydell
        } else {
6124 845ea09a Peter Maydell
            /* Single */
6125 845ea09a Peter Maydell
            TCGv_i32 tcg_op1 = tcg_temp_new_i32();
6126 845ea09a Peter Maydell
            TCGv_i32 tcg_op2 = tcg_temp_new_i32();
6127 845ea09a Peter Maydell
            TCGv_i32 tcg_res = tcg_temp_new_i32();
6128 845ea09a Peter Maydell
6129 845ea09a Peter Maydell
            read_vec_element_i32(s, tcg_op1, rn, pass, MO_32);
6130 845ea09a Peter Maydell
            read_vec_element_i32(s, tcg_op2, rm, pass, MO_32);
6131 845ea09a Peter Maydell
6132 845ea09a Peter Maydell
            switch (fpopcode) {
6133 057d5f62 Peter Maydell
            case 0x39: /* FMLS */
6134 057d5f62 Peter Maydell
                /* As usual for ARM, separate negation for fused multiply-add */
6135 057d5f62 Peter Maydell
                gen_helper_vfp_negs(tcg_op1, tcg_op1);
6136 057d5f62 Peter Maydell
                /* fall through */
6137 057d5f62 Peter Maydell
            case 0x19: /* FMLA */
6138 057d5f62 Peter Maydell
                read_vec_element_i32(s, tcg_res, rd, pass, MO_32);
6139 057d5f62 Peter Maydell
                gen_helper_vfp_muladds(tcg_res, tcg_op1, tcg_op2,
6140 057d5f62 Peter Maydell
                                       tcg_res, fpst);
6141 057d5f62 Peter Maydell
                break;
6142 845ea09a Peter Maydell
            case 0x1a: /* FADD */
6143 845ea09a Peter Maydell
                gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
6144 845ea09a Peter Maydell
                break;
6145 057d5f62 Peter Maydell
            case 0x1b: /* FMULX */
6146 057d5f62 Peter Maydell
                gen_helper_vfp_mulxs(tcg_res, tcg_op1, tcg_op2, fpst);
6147 057d5f62 Peter Maydell
                break;
6148 8908f4d1 Alex Bennée
            case 0x1c: /* FCMEQ */
6149 8908f4d1 Alex Bennée
                gen_helper_neon_ceq_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6150 8908f4d1 Alex Bennée
                break;
6151 845ea09a Peter Maydell
            case 0x1e: /* FMAX */
6152 845ea09a Peter Maydell
                gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
6153 845ea09a Peter Maydell
                break;
6154 057d5f62 Peter Maydell
            case 0x1f: /* FRECPS */
6155 057d5f62 Peter Maydell
                gen_helper_recpsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6156 057d5f62 Peter Maydell
                break;
6157 845ea09a Peter Maydell
            case 0x18: /* FMAXNM */
6158 845ea09a Peter Maydell
                gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
6159 845ea09a Peter Maydell
                break;
6160 845ea09a Peter Maydell
            case 0x38: /* FMINNM */
6161 845ea09a Peter Maydell
                gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
6162 845ea09a Peter Maydell
                break;
6163 845ea09a Peter Maydell
            case 0x3a: /* FSUB */
6164 845ea09a Peter Maydell
                gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
6165 845ea09a Peter Maydell
                break;
6166 845ea09a Peter Maydell
            case 0x3e: /* FMIN */
6167 845ea09a Peter Maydell
                gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
6168 845ea09a Peter Maydell
                break;
6169 057d5f62 Peter Maydell
            case 0x3f: /* FRSQRTS */
6170 057d5f62 Peter Maydell
                gen_helper_rsqrtsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6171 057d5f62 Peter Maydell
                break;
6172 845ea09a Peter Maydell
            case 0x5b: /* FMUL */
6173 845ea09a Peter Maydell
                gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
6174 845ea09a Peter Maydell
                break;
6175 8908f4d1 Alex Bennée
            case 0x5c: /* FCMGE */
6176 8908f4d1 Alex Bennée
                gen_helper_neon_cge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6177 8908f4d1 Alex Bennée
                break;
6178 057d5f62 Peter Maydell
            case 0x5d: /* FACGE */
6179 057d5f62 Peter Maydell
                gen_helper_neon_acge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6180 057d5f62 Peter Maydell
                break;
6181 845ea09a Peter Maydell
            case 0x5f: /* FDIV */
6182 845ea09a Peter Maydell
                gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst);
6183 845ea09a Peter Maydell
                break;
6184 845ea09a Peter Maydell
            case 0x7a: /* FABD */
6185 845ea09a Peter Maydell
                gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
6186 845ea09a Peter Maydell
                gen_helper_vfp_abss(tcg_res, tcg_res);
6187 845ea09a Peter Maydell
                break;
6188 8908f4d1 Alex Bennée
            case 0x7c: /* FCMGT */
6189 8908f4d1 Alex Bennée
                gen_helper_neon_cgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6190 8908f4d1 Alex Bennée
                break;
6191 057d5f62 Peter Maydell
            case 0x7d: /* FACGT */
6192 057d5f62 Peter Maydell
                gen_helper_neon_acgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
6193 057d5f62 Peter Maydell
                break;
6194 845ea09a Peter Maydell
            default:
6195 845ea09a Peter Maydell
                g_assert_not_reached();
6196 845ea09a Peter Maydell
            }
6197 845ea09a Peter Maydell
6198 845ea09a Peter Maydell
            if (elements == 1) {
6199 845ea09a Peter Maydell
                /* scalar single so clear high part */
6200 845ea09a Peter Maydell
                TCGv_i64 tcg_tmp = tcg_temp_new_i64();
6201 845ea09a Peter Maydell
6202 845ea09a Peter Maydell
                tcg_gen_extu_i32_i64(tcg_tmp, tcg_res);
6203 845ea09a Peter Maydell
                write_vec_element(s, tcg_tmp, rd, pass, MO_64);
6204 845ea09a Peter Maydell
                tcg_temp_free_i64(tcg_tmp);
6205 845ea09a Peter Maydell
            } else {
6206 845ea09a Peter Maydell
                write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
6207 845ea09a Peter Maydell
            }
6208 845ea09a Peter Maydell
6209 845ea09a Peter Maydell
            tcg_temp_free_i32(tcg_res);
6210 845ea09a Peter Maydell
            tcg_temp_free_i32(tcg_op1);
6211 845ea09a Peter Maydell
            tcg_temp_free_i32(tcg_op2);
6212 845ea09a Peter Maydell
        }
6213 845ea09a Peter Maydell
    }
6214 845ea09a Peter Maydell
6215 845ea09a Peter Maydell
    tcg_temp_free_ptr(fpst);
6216 845ea09a Peter Maydell
6217 845ea09a Peter Maydell
    if ((elements << size) < 4) {
6218 845ea09a Peter Maydell
        /* scalar, or non-quad vector op */
6219 845ea09a Peter Maydell
        clear_vec_high(s, rd);
6220 845ea09a Peter Maydell
    }
6221 845ea09a Peter Maydell
}
6222 845ea09a Peter Maydell
6223 384b26fb Alex Bennée
/* C3.6.11 AdvSIMD scalar three same
6224 384b26fb Alex Bennée
 *  31 30  29 28       24 23  22  21 20  16 15    11  10 9    5 4    0
6225 384b26fb Alex Bennée
 * +-----+---+-----------+------+---+------+--------+---+------+------+
6226 384b26fb Alex Bennée
 * | 0 1 | U | 1 1 1 1 0 | size | 1 |  Rm  | opcode | 1 |  Rn  |  Rd  |
6227 384b26fb Alex Bennée
 * +-----+---+-----------+------+---+------+--------+---+------+------+
6228 384b26fb Alex Bennée
 */
6229 384b26fb Alex Bennée
static void disas_simd_scalar_three_reg_same(DisasContext *s, uint32_t insn)
6230 384b26fb Alex Bennée
{
6231 b305dba6 Peter Maydell
    int rd = extract32(insn, 0, 5);
6232 b305dba6 Peter Maydell
    int rn = extract32(insn, 5, 5);
6233 b305dba6 Peter Maydell
    int opcode = extract32(insn, 11, 5);
6234 b305dba6 Peter Maydell
    int rm = extract32(insn, 16, 5);
6235 b305dba6 Peter Maydell
    int size = extract32(insn, 22, 2);
6236 b305dba6 Peter Maydell
    bool u = extract32(insn, 29, 1);
6237 b305dba6 Peter Maydell
    TCGv_i64 tcg_rd;
6238 b305dba6 Peter Maydell
6239 b305dba6 Peter Maydell
    if (opcode >= 0x18) {
6240 b305dba6 Peter Maydell
        /* Floating point: U, size[1] and opcode indicate operation */
6241 b305dba6 Peter Maydell
        int fpopcode = opcode | (extract32(size, 1, 1) << 5) | (u << 6);
6242 b305dba6 Peter Maydell
        switch (fpopcode) {
6243 b305dba6 Peter Maydell
        case 0x1b: /* FMULX */
6244 b305dba6 Peter Maydell
        case 0x1f: /* FRECPS */
6245 b305dba6 Peter Maydell
        case 0x3f: /* FRSQRTS */
6246 b305dba6 Peter Maydell
        case 0x5d: /* FACGE */
6247 b305dba6 Peter Maydell
        case 0x7d: /* FACGT */
6248 8908f4d1 Alex Bennée
        case 0x1c: /* FCMEQ */
6249 8908f4d1 Alex Bennée
        case 0x5c: /* FCMGE */
6250 8908f4d1 Alex Bennée
        case 0x7c: /* FCMGT */
6251 845ea09a Peter Maydell
        case 0x7a: /* FABD */
6252 845ea09a Peter Maydell
            break;
6253 b305dba6 Peter Maydell
        default:
6254 b305dba6 Peter Maydell
            unallocated_encoding(s);
6255 b305dba6 Peter Maydell
            return;
6256 b305dba6 Peter Maydell
        }
6257 845ea09a Peter Maydell
6258 845ea09a Peter Maydell
        handle_3same_float(s, extract32(size, 0, 1), 1, fpopcode, rd, rn, rm);
6259 845ea09a Peter Maydell
        return;
6260 b305dba6 Peter Maydell
    }
6261 b305dba6 Peter Maydell
6262 b305dba6 Peter Maydell
    switch (opcode) {
6263 b305dba6 Peter Maydell
    case 0x1: /* SQADD, UQADD */
6264 b305dba6 Peter Maydell
    case 0x5: /* SQSUB, UQSUB */
6265 c0b2b5fa Peter Maydell
    case 0x9: /* SQSHL, UQSHL */
6266 c0b2b5fa Peter Maydell
    case 0xb: /* SQRSHL, UQRSHL */
6267 c0b2b5fa Peter Maydell
        break;
6268 6d9571f7 Peter Maydell
    case 0x8: /* SSHL, USHL */
6269 6d9571f7 Peter Maydell
    case 0xa: /* SRSHL, URSHL */
6270 b305dba6 Peter Maydell
    case 0x6: /* CMGT, CMHI */
6271 b305dba6 Peter Maydell
    case 0x7: /* CMGE, CMHS */
6272 b305dba6 Peter Maydell
    case 0x11: /* CMTST, CMEQ */
6273 b305dba6 Peter Maydell
    case 0x10: /* ADD, SUB (vector) */
6274 b305dba6 Peter Maydell
        if (size != 3) {
6275 b305dba6 Peter Maydell
            unallocated_encoding(s);
6276 b305dba6 Peter Maydell
            return;
6277 b305dba6 Peter Maydell
        }
6278 b305dba6 Peter Maydell
        break;
6279 b305dba6 Peter Maydell
    case 0x16: /* SQDMULH, SQRDMULH (vector) */
6280 b305dba6 Peter Maydell
        if (size != 1 && size != 2) {
6281 b305dba6 Peter Maydell
            unallocated_encoding(s);
6282 b305dba6 Peter Maydell
            return;
6283 b305dba6 Peter Maydell
        }
6284 c0b2b5fa Peter Maydell
        break;
6285 b305dba6 Peter Maydell
    default:
6286 b305dba6 Peter Maydell
        unallocated_encoding(s);
6287 b305dba6 Peter Maydell
        return;
6288 b305dba6 Peter Maydell
    }
6289 b305dba6 Peter Maydell
6290 b305dba6 Peter Maydell
    tcg_rd = tcg_temp_new_i64();
6291 b305dba6 Peter Maydell
6292 c0b2b5fa Peter Maydell
    if (size == 3) {
6293 c0b2b5fa Peter Maydell
        TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
6294 c0b2b5fa Peter Maydell
        TCGv_i64 tcg_rm = read_fp_dreg(s, rm);
6295 c0b2b5fa Peter Maydell
6296 c0b2b5fa Peter Maydell
        handle_3same_64(s, opcode, u, tcg_rd, tcg_rn, tcg_rm);
6297 c0b2b5fa Peter Maydell
        tcg_temp_free_i64(tcg_rn);
6298 c0b2b5fa Peter Maydell
        tcg_temp_free_i64(tcg_rm);
6299 c0b2b5fa Peter Maydell
    } else {
6300 c0b2b5fa Peter Maydell
        /* Do a single operation on the lowest element in the vector.
6301 c0b2b5fa Peter Maydell
         * We use the standard Neon helpers and rely on 0 OP 0 == 0 with
6302 c0b2b5fa Peter Maydell
         * no side effects for all these operations.
6303 c0b2b5fa Peter Maydell
         * OPTME: special-purpose helpers would avoid doing some
6304 c0b2b5fa Peter Maydell
         * unnecessary work in the helper for the 8 and 16 bit cases.
6305 c0b2b5fa Peter Maydell
         */
6306 c0b2b5fa Peter Maydell
        NeonGenTwoOpEnvFn *genenvfn;
6307 c0b2b5fa Peter Maydell
        TCGv_i32 tcg_rn = tcg_temp_new_i32();
6308 c0b2b5fa Peter Maydell
        TCGv_i32 tcg_rm = tcg_temp_new_i32();
6309 c0b2b5fa Peter Maydell
        TCGv_i32 tcg_rd32 = tcg_temp_new_i32();
6310 c0b2b5fa Peter Maydell
6311 c0b2b5fa Peter Maydell
        read_vec_element_i32(s, tcg_rn, rn, 0, size);
6312 c0b2b5fa Peter Maydell
        read_vec_element_i32(s, tcg_rm, rm, 0, size);
6313 c0b2b5fa Peter Maydell
6314 c0b2b5fa Peter Maydell
        switch (opcode) {
6315 c0b2b5fa Peter Maydell
        case 0x1: /* SQADD, UQADD */
6316 c0b2b5fa Peter Maydell
        {
6317 c0b2b5fa Peter Maydell
            static NeonGenTwoOpEnvFn * const fns[3][2] = {
6318 c0b2b5fa Peter Maydell
                { gen_helper_neon_qadd_s8, gen_helper_neon_qadd_u8 },
6319 c0b2b5fa Peter Maydell
                { gen_helper_neon_qadd_s16, gen_helper_neon_qadd_u16 },
6320 c0b2b5fa Peter Maydell
                { gen_helper_neon_qadd_s32, gen_helper_neon_qadd_u32 },
6321 c0b2b5fa Peter Maydell
            };
6322 c0b2b5fa Peter Maydell
            genenvfn = fns[size][u];
6323 c0b2b5fa Peter Maydell
            break;
6324 c0b2b5fa Peter Maydell
        }
6325 c0b2b5fa Peter Maydell
        case 0x5: /* SQSUB, UQSUB */
6326 c0b2b5fa Peter Maydell
        {
6327 c0b2b5fa Peter Maydell
            static NeonGenTwoOpEnvFn * const fns[3][2] = {
6328 c0b2b5fa Peter Maydell
                { gen_helper_neon_qsub_s8, gen_helper_neon_qsub_u8 },
6329 c0b2b5fa Peter Maydell
                { gen_helper_neon_qsub_s16, gen_helper_neon_qsub_u16 },
6330 c0b2b5fa Peter Maydell
                { gen_helper_neon_qsub_s32, gen_helper_neon_qsub_u32 },
6331 c0b2b5fa Peter Maydell
            };
6332 c0b2b5fa Peter Maydell
            genenvfn = fns[size][u];
6333 c0b2b5fa Peter Maydell
            break;
6334 c0b2b5fa Peter Maydell
        }
6335 c0b2b5fa Peter Maydell
        case 0x9: /* SQSHL, UQSHL */
6336 c0b2b5fa Peter Maydell
        {
6337 c0b2b5fa Peter Maydell
            static NeonGenTwoOpEnvFn * const fns[3][2] = {
6338 c0b2b5fa Peter Maydell
                { gen_helper_neon_qshl_s8, gen_helper_neon_qshl_u8 },
6339 c0b2b5fa Peter Maydell
                { gen_helper_neon_qshl_s16, gen_helper_neon_qshl_u16 },
6340 c0b2b5fa Peter Maydell
                { gen_helper_neon_qshl_s32, gen_helper_neon_qshl_u32 },
6341 c0b2b5fa Peter Maydell
            };
6342 c0b2b5fa Peter Maydell
            genenvfn = fns[size][u];
6343 c0b2b5fa Peter Maydell
            break;
6344 c0b2b5fa Peter Maydell
        }
6345 c0b2b5fa Peter Maydell
        case 0xb: /* SQRSHL, UQRSHL */
6346 c0b2b5fa Peter Maydell
        {
6347 c0b2b5fa Peter Maydell
            static NeonGenTwoOpEnvFn * const fns[3][2] = {
6348 c0b2b5fa Peter Maydell
                { gen_helper_neon_qrshl_s8, gen_helper_neon_qrshl_u8 },
6349 c0b2b5fa Peter Maydell
                { gen_helper_neon_qrshl_s16, gen_helper_neon_qrshl_u16 },
6350 c0b2b5fa Peter Maydell
                { gen_helper_neon_qrshl_s32, gen_helper_neon_qrshl_u32 },
6351 c0b2b5fa Peter Maydell
            };
6352 c0b2b5fa Peter Maydell
            genenvfn = fns[size][u];
6353 c0b2b5fa Peter Maydell
            break;
6354 c0b2b5fa Peter Maydell
        }
6355 c0b2b5fa Peter Maydell
        case 0x16: /* SQDMULH, SQRDMULH */
6356 c0b2b5fa Peter Maydell
        {
6357 c0b2b5fa Peter Maydell
            static NeonGenTwoOpEnvFn * const fns[2][2] = {
6358 c0b2b5fa Peter Maydell
                { gen_helper_neon_qdmulh_s16, gen_helper_neon_qrdmulh_s16 },
6359 c0b2b5fa Peter Maydell
                { gen_helper_neon_qdmulh_s32, gen_helper_neon_qrdmulh_s32 },
6360 c0b2b5fa Peter Maydell
            };
6361 c0b2b5fa Peter Maydell
            assert(size == 1 || size == 2);
6362 c0b2b5fa Peter Maydell
            genenvfn = fns[size - 1][u];
6363 c0b2b5fa Peter Maydell
            break;
6364 c0b2b5fa Peter Maydell
        }
6365 c0b2b5fa Peter Maydell
        default:
6366 c0b2b5fa Peter Maydell
            g_assert_not_reached();
6367 c0b2b5fa Peter Maydell
        }
6368 c0b2b5fa Peter Maydell
6369 c0b2b5fa Peter Maydell
        genenvfn(tcg_rd32, cpu_env, tcg_rn, tcg_rm);
6370 c0b2b5fa Peter Maydell
        tcg_gen_extu_i32_i64(tcg_rd, tcg_rd32);
6371 c0b2b5fa Peter Maydell
        tcg_temp_free_i32(tcg_rd32);
6372 c0b2b5fa Peter Maydell
        tcg_temp_free_i32(tcg_rn);
6373 c0b2b5fa Peter Maydell
        tcg_temp_free_i32(tcg_rm);
6374 c0b2b5fa Peter Maydell
    }
6375 b305dba6 Peter Maydell
6376 b305dba6 Peter Maydell
    write_fp_dreg(s, rd, tcg_rd);
6377 b305dba6 Peter Maydell
6378 b305dba6 Peter Maydell
    tcg_temp_free_i64(tcg_rd);
6379 384b26fb Alex Bennée
}
6380 384b26fb Alex Bennée
6381 effa8e06 Peter Maydell
static void handle_2misc_64(DisasContext *s, int opcode, bool u,
6382 effa8e06 Peter Maydell
                            TCGv_i64 tcg_rd, TCGv_i64 tcg_rn)
6383 effa8e06 Peter Maydell
{
6384 effa8e06 Peter Maydell
    /* Handle 64->64 opcodes which are shared between the scalar and
6385 effa8e06 Peter Maydell
     * vector 2-reg-misc groups. We cover every integer opcode where size == 3
6386 f93d0138 Peter Maydell
     * is valid in either group and also the double-precision fp ops.
6387 effa8e06 Peter Maydell
     */
6388 effa8e06 Peter Maydell
    TCGCond cond;
6389 effa8e06 Peter Maydell
6390 effa8e06 Peter Maydell
    switch (opcode) {
6391 86cbc418 Peter Maydell
    case 0x5: /* NOT */
6392 86cbc418 Peter Maydell
        /* This opcode is shared with CNT and RBIT but we have earlier
6393 86cbc418 Peter Maydell
         * enforced that size == 3 if and only if this is the NOT insn.
6394 86cbc418 Peter Maydell
         */
6395 86cbc418 Peter Maydell
        tcg_gen_not_i64(tcg_rd, tcg_rn);
6396 86cbc418 Peter Maydell
        break;
6397 effa8e06 Peter Maydell
    case 0xa: /* CMLT */
6398 effa8e06 Peter Maydell
        /* 64 bit integer comparison against zero, result is
6399 effa8e06 Peter Maydell
         * test ? (2^64 - 1) : 0. We implement via setcond(!test) and
6400 effa8e06 Peter Maydell
         * subtracting 1.
6401 effa8e06 Peter Maydell
         */
6402 effa8e06 Peter Maydell
        cond = TCG_COND_LT;
6403 effa8e06 Peter Maydell
    do_cmop:
6404 effa8e06 Peter Maydell
        tcg_gen_setcondi_i64(cond, tcg_rd, tcg_rn, 0);
6405 effa8e06 Peter Maydell
        tcg_gen_neg_i64(tcg_rd, tcg_rd);
6406 effa8e06 Peter Maydell
        break;
6407 effa8e06 Peter Maydell
    case 0x8: /* CMGT, CMGE */
6408 effa8e06 Peter Maydell
        cond = u ? TCG_COND_GE : TCG_COND_GT;
6409 effa8e06 Peter Maydell
        goto do_cmop;
6410 effa8e06 Peter Maydell
    case 0x9: /* CMEQ, CMLE */
6411 effa8e06 Peter Maydell
        cond = u ? TCG_COND_LE : TCG_COND_EQ;
6412 effa8e06 Peter Maydell
        goto do_cmop;
6413 effa8e06 Peter Maydell
    case 0xb: /* ABS, NEG */
6414 effa8e06 Peter Maydell
        if (u) {
6415 effa8e06 Peter Maydell
            tcg_gen_neg_i64(tcg_rd, tcg_rn);
6416 effa8e06 Peter Maydell
        } else {
6417 effa8e06 Peter Maydell
            TCGv_i64 tcg_zero = tcg_const_i64(0);
6418 effa8e06 Peter Maydell
            tcg_gen_neg_i64(tcg_rd, tcg_rn);
6419 effa8e06 Peter Maydell
            tcg_gen_movcond_i64(TCG_COND_GT, tcg_rd, tcg_rn, tcg_zero,
6420 effa8e06 Peter Maydell
                                tcg_rn, tcg_rd);
6421 effa8e06 Peter Maydell
            tcg_temp_free_i64(tcg_zero);
6422 effa8e06 Peter Maydell
        }
6423 effa8e06 Peter Maydell
        break;
6424 f93d0138 Peter Maydell
    case 0x2f: /* FABS */
6425 f93d0138 Peter Maydell
        gen_helper_vfp_absd(tcg_rd, tcg_rn);
6426 f93d0138 Peter Maydell
        break;
6427 f93d0138 Peter Maydell
    case 0x6f: /* FNEG */
6428 f93d0138 Peter Maydell
        gen_helper_vfp_negd(tcg_rd, tcg_rn);
6429 f93d0138 Peter Maydell
        break;
6430 effa8e06 Peter Maydell
    default:
6431 effa8e06 Peter Maydell
        g_assert_not_reached();
6432 effa8e06 Peter Maydell
    }
6433 effa8e06 Peter Maydell
}
6434 effa8e06 Peter Maydell
6435 8908f4d1 Alex Bennée
static void handle_2misc_fcmp_zero(DisasContext *s, int opcode,
6436 8908f4d1 Alex Bennée
                                   bool is_scalar, bool is_u, bool is_q,
6437 8908f4d1 Alex Bennée
                                   int size, int rn, int rd)
6438 8908f4d1 Alex Bennée
{
6439 8908f4d1 Alex Bennée
    bool is_double = (size == 3);
6440 8908f4d1 Alex Bennée
    TCGv_ptr fpst = get_fpstatus_ptr();
6441 8908f4d1 Alex Bennée
6442 8908f4d1 Alex Bennée
    if (is_double) {
6443 8908f4d1 Alex Bennée
        TCGv_i64 tcg_op = tcg_temp_new_i64();
6444 8908f4d1 Alex Bennée
        TCGv_i64 tcg_zero = tcg_const_i64(0);
6445 8908f4d1 Alex Bennée
        TCGv_i64 tcg_res = tcg_temp_new_i64();
6446 8908f4d1 Alex Bennée
        NeonGenTwoDoubleOPFn *genfn;
6447 8908f4d1 Alex Bennée
        bool swap = false;
6448 8908f4d1 Alex Bennée
        int pass;
6449 8908f4d1 Alex Bennée
6450 8908f4d1 Alex Bennée
        switch (opcode) {
6451 8908f4d1 Alex Bennée
        case 0x2e: /* FCMLT (zero) */
6452 8908f4d1 Alex Bennée
            swap = true;
6453 8908f4d1 Alex Bennée
            /* fallthrough */
6454 8908f4d1 Alex Bennée
        case 0x2c: /* FCMGT (zero) */
6455 8908f4d1 Alex Bennée
            genfn = gen_helper_neon_cgt_f64;
6456 8908f4d1 Alex Bennée
            break;
6457 8908f4d1 Alex Bennée
        case 0x2d: /* FCMEQ (zero) */
6458 8908f4d1 Alex Bennée
            genfn = gen_helper_neon_ceq_f64;
6459 8908f4d1 Alex Bennée
            break;
6460 8908f4d1 Alex Bennée
        case 0x6d: /* FCMLE (zero) */
6461 8908f4d1 Alex Bennée
            swap = true;
6462 8908f4d1 Alex Bennée
            /* fall through */
6463 8908f4d1 Alex Bennée
        case 0x6c: /* FCMGE (zero) */
6464 8908f4d1 Alex Bennée
            genfn = gen_helper_neon_cge_f64;
6465 8908f4d1 Alex Bennée
            break;
6466 8908f4d1 Alex Bennée
        default:
6467 8908f4d1 Alex Bennée
            g_assert_not_reached();
6468 8908f4d1 Alex Bennée
        }
6469 8908f4d1 Alex Bennée
6470 8908f4d1 Alex Bennée
        for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
6471 8908f4d1 Alex Bennée
            read_vec_element(s, tcg_op, rn, pass, MO_64);
6472 8908f4d1 Alex Bennée
            if (swap) {
6473 8908f4d1 Alex Bennée
                genfn(tcg_res, tcg_zero, tcg_op, fpst);
6474 8908f4d1 Alex Bennée
            } else {
6475 8908f4d1 Alex Bennée
                genfn(tcg_res, tcg_op, tcg_zero, fpst);
6476 8908f4d1 Alex Bennée
            }
6477 8908f4d1 Alex Bennée
            write_vec_element(s, tcg_res, rd, pass, MO_64);
6478 8908f4d1 Alex Bennée
        }
6479 8908f4d1 Alex Bennée
        if (is_scalar) {
6480 8908f4d1 Alex Bennée
            clear_vec_high(s, rd);
6481 8908f4d1 Alex Bennée
        }
6482 8908f4d1 Alex Bennée
6483 8908f4d1 Alex Bennée
        tcg_temp_free_i64(tcg_res);
6484 8908f4d1 Alex Bennée
        tcg_temp_free_i64(tcg_zero);
6485 8908f4d1 Alex Bennée
        tcg_temp_free_i64(tcg_op);
6486 8908f4d1 Alex Bennée
    } else {
6487 8908f4d1 Alex Bennée
        TCGv_i32 tcg_op = tcg_temp_new_i32();
6488 8908f4d1 Alex Bennée
        TCGv_i32 tcg_zero = tcg_const_i32(0);
6489 8908f4d1 Alex Bennée
        TCGv_i32 tcg_res = tcg_temp_new_i32();
6490 8908f4d1 Alex Bennée
        NeonGenTwoSingleOPFn *genfn;
6491 8908f4d1 Alex Bennée
        bool swap = false;
6492 8908f4d1 Alex Bennée
        int pass, maxpasses;
6493 8908f4d1 Alex Bennée
6494 8908f4d1 Alex Bennée
        switch (opcode) {
6495 8908f4d1 Alex Bennée
        case 0x2e: /* FCMLT (zero) */
6496 8908f4d1 Alex Bennée
            swap = true;
6497 8908f4d1 Alex Bennée
            /* fall through */
6498 8908f4d1 Alex Bennée
        case 0x2c: /* FCMGT (zero) */
6499 8908f4d1 Alex Bennée
            genfn = gen_helper_neon_cgt_f32;
6500 8908f4d1 Alex Bennée
            break;
6501 8908f4d1 Alex Bennée
        case 0x2d: /* FCMEQ (zero) */
6502 8908f4d1 Alex Bennée
            genfn = gen_helper_neon_ceq_f32;
6503 8908f4d1 Alex Bennée
            break;
6504 8908f4d1 Alex Bennée
        case 0x6d: /* FCMLE (zero) */
6505 8908f4d1 Alex Bennée
            swap = true;
6506 8908f4d1 Alex Bennée
            /* fall through */
6507 8908f4d1 Alex Bennée
        case 0x6c: /* FCMGE (zero) */
6508 8908f4d1 Alex Bennée
            genfn = gen_helper_neon_cge_f32;
6509 8908f4d1 Alex Bennée
            break;
6510 8908f4d1 Alex Bennée
        default:
6511 8908f4d1 Alex Bennée
            g_assert_not_reached();
6512 8908f4d1 Alex Bennée
        }
6513 8908f4d1 Alex Bennée
6514 8908f4d1 Alex Bennée
        if (is_scalar) {
6515 8908f4d1 Alex Bennée
            maxpasses = 1;
6516 8908f4d1 Alex Bennée
        } else {
6517 8908f4d1 Alex Bennée
            maxpasses = is_q ? 4 : 2;
6518 8908f4d1 Alex Bennée
        }
6519 8908f4d1 Alex Bennée
6520 8908f4d1 Alex Bennée
        for (pass = 0; pass < maxpasses; pass++) {
6521 8908f4d1 Alex Bennée
            read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
6522 8908f4d1 Alex Bennée
            if (swap) {
6523 8908f4d1 Alex Bennée
                genfn(tcg_res, tcg_zero, tcg_op, fpst);
6524 8908f4d1 Alex Bennée
            } else {
6525 8908f4d1 Alex Bennée
                genfn(tcg_res, tcg_op, tcg_zero, fpst);
6526 8908f4d1 Alex Bennée
            }
6527 8908f4d1 Alex Bennée
            if (is_scalar) {
6528 8908f4d1 Alex Bennée
                write_fp_sreg(s, rd, tcg_res);
6529 8908f4d1 Alex Bennée
            } else {
6530 8908f4d1 Alex Bennée
                write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
6531 8908f4d1 Alex Bennée
            }
6532 8908f4d1 Alex Bennée
        }
6533 8908f4d1 Alex Bennée
        tcg_temp_free_i32(tcg_res);
6534 8908f4d1 Alex Bennée
        tcg_temp_free_i32(tcg_zero);
6535 8908f4d1 Alex Bennée
        tcg_temp_free_i32(tcg_op);
6536 8908f4d1 Alex Bennée
        if (!is_q && !is_scalar) {
6537 8908f4d1 Alex Bennée
            clear_vec_high(s, rd);
6538 8908f4d1 Alex Bennée
        }
6539 8908f4d1 Alex Bennée
    }
6540 8908f4d1 Alex Bennée
6541 8908f4d1 Alex Bennée
    tcg_temp_free_ptr(fpst);
6542 8908f4d1 Alex Bennée
}
6543 8908f4d1 Alex Bennée
6544 384b26fb Alex Bennée
/* C3.6.12 AdvSIMD scalar two reg misc
6545 384b26fb Alex Bennée
 *  31 30  29 28       24 23  22 21       17 16    12 11 10 9    5 4    0
6546 384b26fb Alex Bennée
 * +-----+---+-----------+------+-----------+--------+-----+------+------+
6547 384b26fb Alex Bennée
 * | 0 1 | U | 1 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 |  Rn  |  Rd  |
6548 384b26fb Alex Bennée
 * +-----+---+-----------+------+-----------+--------+-----+------+------+
6549 384b26fb Alex Bennée
 */
6550 384b26fb Alex Bennée
static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn)
6551 384b26fb Alex Bennée
{
6552 effa8e06 Peter Maydell
    int rd = extract32(insn, 0, 5);
6553 effa8e06 Peter Maydell
    int rn = extract32(insn, 5, 5);
6554 effa8e06 Peter Maydell
    int opcode = extract32(insn, 12, 5);
6555 effa8e06 Peter Maydell
    int size = extract32(insn, 22, 2);
6556 effa8e06 Peter Maydell
    bool u = extract32(insn, 29, 1);
6557 effa8e06 Peter Maydell
6558 effa8e06 Peter Maydell
    switch (opcode) {
6559 effa8e06 Peter Maydell
    case 0xa: /* CMLT */
6560 effa8e06 Peter Maydell
        if (u) {
6561 effa8e06 Peter Maydell
            unallocated_encoding(s);
6562 effa8e06 Peter Maydell
            return;
6563 effa8e06 Peter Maydell
        }
6564 effa8e06 Peter Maydell
        /* fall through */
6565 effa8e06 Peter Maydell
    case 0x8: /* CMGT, CMGE */
6566 effa8e06 Peter Maydell
    case 0x9: /* CMEQ, CMLE */
6567 effa8e06 Peter Maydell
    case 0xb: /* ABS, NEG */
6568 effa8e06 Peter Maydell
        if (size != 3) {
6569 effa8e06 Peter Maydell
            unallocated_encoding(s);
6570 effa8e06 Peter Maydell
            return;
6571 effa8e06 Peter Maydell
        }
6572 effa8e06 Peter Maydell
        break;
6573 8908f4d1 Alex Bennée
    case 0xc ... 0xf:
6574 8908f4d1 Alex Bennée
    case 0x16 ... 0x1d:
6575 8908f4d1 Alex Bennée
    case 0x1f:
6576 8908f4d1 Alex Bennée
        /* Floating point: U, size[1] and opcode indicate operation;
6577 8908f4d1 Alex Bennée
         * size[0] indicates single or double precision.
6578 8908f4d1 Alex Bennée
         */
6579 8908f4d1 Alex Bennée
        opcode |= (extract32(size, 1, 1) << 5) | (u << 6);
6580 8908f4d1 Alex Bennée
        size = extract32(size, 0, 1) ? 3 : 2;
6581 8908f4d1 Alex Bennée
        switch (opcode) {
6582 8908f4d1 Alex Bennée
        case 0x2c: /* FCMGT (zero) */
6583 8908f4d1 Alex Bennée
        case 0x2d: /* FCMEQ (zero) */
6584 8908f4d1 Alex Bennée
        case 0x2e: /* FCMLT (zero) */
6585 8908f4d1 Alex Bennée
        case 0x6c: /* FCMGE (zero) */
6586 8908f4d1 Alex Bennée
        case 0x6d: /* FCMLE (zero) */
6587 8908f4d1 Alex Bennée
            handle_2misc_fcmp_zero(s, opcode, true, u, true, size, rn, rd);
6588 8908f4d1 Alex Bennée
            return;
6589 8908f4d1 Alex Bennée
        case 0x1a: /* FCVTNS */
6590 8908f4d1 Alex Bennée
        case 0x1b: /* FCVTMS */
6591 8908f4d1 Alex Bennée
        case 0x1c: /* FCVTAS */
6592 8908f4d1 Alex Bennée
        case 0x1d: /* SCVTF */
6593 8908f4d1 Alex Bennée
        case 0x3a: /* FCVTPS */
6594 8908f4d1 Alex Bennée
        case 0x3b: /* FCVTZS */
6595 8908f4d1 Alex Bennée
        case 0x3d: /* FRECPE */
6596 8908f4d1 Alex Bennée
        case 0x3f: /* FRECPX */
6597 8908f4d1 Alex Bennée
        case 0x56: /* FCVTXN, FCVTXN2 */
6598 8908f4d1 Alex Bennée
        case 0x5a: /* FCVTNU */
6599 8908f4d1 Alex Bennée
        case 0x5b: /* FCVTMU */
6600 8908f4d1 Alex Bennée
        case 0x5c: /* FCVTAU */
6601 8908f4d1 Alex Bennée
        case 0x5d: /* UCVTF */
6602 8908f4d1 Alex Bennée
        case 0x7a: /* FCVTPU */
6603 8908f4d1 Alex Bennée
        case 0x7b: /* FCVTZU */
6604 8908f4d1 Alex Bennée
        case 0x7d: /* FRSQRTE */
6605 8908f4d1 Alex Bennée
            unsupported_encoding(s, insn);
6606 8908f4d1 Alex Bennée
            return;
6607 8908f4d1 Alex Bennée
        default:
6608 8908f4d1 Alex Bennée
            unallocated_encoding(s);
6609 8908f4d1 Alex Bennée
            return;
6610 8908f4d1 Alex Bennée
        }
6611 8908f4d1 Alex Bennée
        break;
6612 effa8e06 Peter Maydell
    default:
6613 effa8e06 Peter Maydell
        /* Other categories of encoding in this class:
6614 effa8e06 Peter Maydell
         *  + SUQADD/USQADD/SQABS/SQNEG : size 8, 16, 32 or 64
6615 effa8e06 Peter Maydell
         *  + SQXTN/SQXTN2/SQXTUN/SQXTUN2/UQXTN/UQXTN2:
6616 effa8e06 Peter Maydell
         *    narrowing saturate ops: size 64/32/16 -> 32/16/8
6617 effa8e06 Peter Maydell
         */
6618 effa8e06 Peter Maydell
        unsupported_encoding(s, insn);
6619 effa8e06 Peter Maydell
        return;
6620 effa8e06 Peter Maydell
    }
6621 effa8e06 Peter Maydell
6622 effa8e06 Peter Maydell
    if (size == 3) {
6623 effa8e06 Peter Maydell
        TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
6624 effa8e06 Peter Maydell
        TCGv_i64 tcg_rd = tcg_temp_new_i64();
6625 effa8e06 Peter Maydell
6626 effa8e06 Peter Maydell
        handle_2misc_64(s, opcode, u, tcg_rd, tcg_rn);
6627 effa8e06 Peter Maydell
        write_fp_dreg(s, rd, tcg_rd);
6628 effa8e06 Peter Maydell
        tcg_temp_free_i64(tcg_rd);
6629 effa8e06 Peter Maydell
        tcg_temp_free_i64(tcg_rn);
6630 effa8e06 Peter Maydell
    } else {
6631 effa8e06 Peter Maydell
        /* the 'size might not be 64' ops aren't implemented yet */
6632 effa8e06 Peter Maydell
        g_assert_not_reached();
6633 effa8e06 Peter Maydell
    }
6634 384b26fb Alex Bennée
}
6635 384b26fb Alex Bennée
6636 4d1cef84 Alex Bennée
/* SSHR[RA]/USHR[RA] - Vector shift right (optional rounding/accumulate) */
6637 4d1cef84 Alex Bennée
static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u,
6638 4d1cef84 Alex Bennée
                                 int immh, int immb, int opcode, int rn, int rd)
6639 4d1cef84 Alex Bennée
{
6640 4d1cef84 Alex Bennée
    int size = 32 - clz32(immh) - 1;
6641 4d1cef84 Alex Bennée
    int immhb = immh << 3 | immb;
6642 4d1cef84 Alex Bennée
    int shift = 2 * (8 << size) - immhb;
6643 4d1cef84 Alex Bennée
    bool accumulate = false;
6644 4d1cef84 Alex Bennée
    bool round = false;
6645 4d1cef84 Alex Bennée
    int dsize = is_q ? 128 : 64;
6646 4d1cef84 Alex Bennée
    int esize = 8 << size;
6647 4d1cef84 Alex Bennée
    int elements = dsize/esize;
6648 4d1cef84 Alex Bennée
    TCGMemOp memop = size | (is_u ? 0 : MO_SIGN);
6649 4d1cef84 Alex Bennée
    TCGv_i64 tcg_rn = new_tmp_a64(s);
6650 4d1cef84 Alex Bennée
    TCGv_i64 tcg_rd = new_tmp_a64(s);
6651 4d1cef84 Alex Bennée
    TCGv_i64 tcg_round;
6652 4d1cef84 Alex Bennée
    int i;
6653 4d1cef84 Alex Bennée
6654 4d1cef84 Alex Bennée
    if (extract32(immh, 3, 1) && !is_q) {
6655 4d1cef84 Alex Bennée
        unallocated_encoding(s);
6656 4d1cef84 Alex Bennée
        return;
6657 4d1cef84 Alex Bennée
    }
6658 4d1cef84 Alex Bennée
6659 4d1cef84 Alex Bennée
    if (size > 3 && !is_q) {
6660 4d1cef84 Alex Bennée
        unallocated_encoding(s);
6661 4d1cef84 Alex Bennée
        return;
6662 4d1cef84 Alex Bennée
    }
6663 4d1cef84 Alex Bennée
6664 4d1cef84 Alex Bennée
    switch (opcode) {
6665 4d1cef84 Alex Bennée
    case 0x02: /* SSRA / USRA (accumulate) */
6666 4d1cef84 Alex Bennée
        accumulate = true;
6667 4d1cef84 Alex Bennée
        break;
6668 4d1cef84 Alex Bennée
    case 0x04: /* SRSHR / URSHR (rounding) */
6669 4d1cef84 Alex Bennée
        round = true;
6670 4d1cef84 Alex Bennée
        break;
6671 4d1cef84 Alex Bennée
    case 0x06: /* SRSRA / URSRA (accum + rounding) */
6672 4d1cef84 Alex Bennée
        accumulate = round = true;
6673 4d1cef84 Alex Bennée
        break;
6674 4d1cef84 Alex Bennée
    }
6675 4d1cef84 Alex Bennée
6676 4d1cef84 Alex Bennée
    if (round) {
6677 4d1cef84 Alex Bennée
        uint64_t round_const = 1ULL << (shift - 1);
6678 4d1cef84 Alex Bennée
        tcg_round = tcg_const_i64(round_const);
6679 4d1cef84 Alex Bennée
    } else {
6680 4d1cef84 Alex Bennée
        TCGV_UNUSED_I64(tcg_round);
6681 4d1cef84 Alex Bennée
    }
6682 4d1cef84 Alex Bennée
6683 4d1cef84 Alex Bennée
    for (i = 0; i < elements; i++) {
6684 4d1cef84 Alex Bennée
        read_vec_element(s, tcg_rn, rn, i, memop);
6685 4d1cef84 Alex Bennée
        if (accumulate) {
6686 4d1cef84 Alex Bennée
            read_vec_element(s, tcg_rd, rd, i, memop);
6687 4d1cef84 Alex Bennée
        }
6688 4d1cef84 Alex Bennée
6689 4d1cef84 Alex Bennée
        handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
6690 4d1cef84 Alex Bennée
                                accumulate, is_u, size, shift);
6691 4d1cef84 Alex Bennée
6692 4d1cef84 Alex Bennée
        write_vec_element(s, tcg_rd, rd, i, size);
6693 4d1cef84 Alex Bennée
    }
6694 4d1cef84 Alex Bennée
6695 4d1cef84 Alex Bennée
    if (!is_q) {
6696 4d1cef84 Alex Bennée
        clear_vec_high(s, rd);
6697 4d1cef84 Alex Bennée
    }
6698 4d1cef84 Alex Bennée
6699 4d1cef84 Alex Bennée
    if (round) {
6700 4d1cef84 Alex Bennée
        tcg_temp_free_i64(tcg_round);
6701 4d1cef84 Alex Bennée
    }
6702 4d1cef84 Alex Bennée
}
6703 4d1cef84 Alex Bennée
6704 4d1cef84 Alex Bennée
/* SHL/SLI - Vector shift left */
6705 4d1cef84 Alex Bennée
static void handle_vec_simd_shli(DisasContext *s, bool is_q, bool insert,
6706 4d1cef84 Alex Bennée
                                int immh, int immb, int opcode, int rn, int rd)
6707 4d1cef84 Alex Bennée
{
6708 4d1cef84 Alex Bennée
    int size = 32 - clz32(immh) - 1;
6709 4d1cef84 Alex Bennée
    int immhb = immh << 3 | immb;
6710 4d1cef84 Alex Bennée
    int shift = immhb - (8 << size);
6711 4d1cef84 Alex Bennée
    int dsize = is_q ? 128 : 64;
6712 4d1cef84 Alex Bennée
    int esize = 8 << size;
6713 4d1cef84 Alex Bennée
    int elements = dsize/esize;
6714 4d1cef84 Alex Bennée
    TCGv_i64 tcg_rn = new_tmp_a64(s);
6715 4d1cef84 Alex Bennée
    TCGv_i64 tcg_rd = new_tmp_a64(s);
6716 4d1cef84 Alex Bennée
    int i;
6717 4d1cef84 Alex Bennée
6718 4d1cef84 Alex Bennée
    if (extract32(immh, 3, 1) && !is_q) {
6719 4d1cef84 Alex Bennée
        unallocated_encoding(s);
6720 4d1cef84 Alex Bennée
        return;
6721 4d1cef84 Alex Bennée
    }
6722 4d1cef84 Alex Bennée
6723 4d1cef84 Alex Bennée
    if (size > 3 && !is_q) {
6724 4d1cef84 Alex Bennée
        unallocated_encoding(s);
6725 4d1cef84 Alex Bennée
        return;
6726 4d1cef84 Alex Bennée
    }
6727 4d1cef84 Alex Bennée
6728 4d1cef84 Alex Bennée
    for (i = 0; i < elements; i++) {
6729 4d1cef84 Alex Bennée
        read_vec_element(s, tcg_rn, rn, i, size);
6730 4d1cef84 Alex Bennée
        if (insert) {
6731 4d1cef84 Alex Bennée
            read_vec_element(s, tcg_rd, rd, i, size);
6732 4d1cef84 Alex Bennée
        }
6733 4d1cef84 Alex Bennée
6734 4d1cef84 Alex Bennée
        handle_shli_with_ins(tcg_rd, tcg_rn, insert, shift);
6735 4d1cef84 Alex Bennée
6736 4d1cef84 Alex Bennée
        write_vec_element(s, tcg_rd, rd, i, size);
6737 4d1cef84 Alex Bennée
    }
6738 4d1cef84 Alex Bennée
6739 4d1cef84 Alex Bennée
    if (!is_q) {
6740 4d1cef84 Alex Bennée
        clear_vec_high(s, rd);
6741 4d1cef84 Alex Bennée
    }
6742 4d1cef84 Alex Bennée
}
6743 4d1cef84 Alex Bennée
6744 4d1cef84 Alex Bennée
/* USHLL/SHLL - Vector shift left with widening */
6745 4d1cef84 Alex Bennée
static void handle_vec_simd_wshli(DisasContext *s, bool is_q, bool is_u,
6746 4d1cef84 Alex Bennée
                                 int immh, int immb, int opcode, int rn, int rd)
6747 4d1cef84 Alex Bennée
{
6748 4d1cef84 Alex Bennée
    int size = 32 - clz32(immh) - 1;
6749 4d1cef84 Alex Bennée
    int immhb = immh << 3 | immb;
6750 4d1cef84 Alex Bennée
    int shift = immhb - (8 << size);
6751 4d1cef84 Alex Bennée
    int dsize = 64;
6752 4d1cef84 Alex Bennée
    int esize = 8 << size;
6753 4d1cef84 Alex Bennée
    int elements = dsize/esize;
6754 4d1cef84 Alex Bennée
    TCGv_i64 tcg_rn = new_tmp_a64(s);
6755 4d1cef84 Alex Bennée
    TCGv_i64 tcg_rd = new_tmp_a64(s);
6756 4d1cef84 Alex Bennée
    int i;
6757 4d1cef84 Alex Bennée
6758 4d1cef84 Alex Bennée
    if (size >= 3) {
6759 4d1cef84 Alex Bennée
        unallocated_encoding(s);
6760 4d1cef84 Alex Bennée
        return;
6761 4d1cef84 Alex Bennée
    }
6762 4d1cef84 Alex Bennée
6763 4d1cef84 Alex Bennée
    /* For the LL variants the store is larger than the load,
6764 4d1cef84 Alex Bennée
     * so if rd == rn we would overwrite parts of our input.
6765 4d1cef84 Alex Bennée
     * So load everything right now and use shifts in the main loop.
6766 4d1cef84 Alex Bennée
     */
6767 4d1cef84 Alex Bennée
    read_vec_element(s, tcg_rn, rn, is_q ? 1 : 0, MO_64);
6768 4d1cef84 Alex Bennée
6769 4d1cef84 Alex Bennée
    for (i = 0; i < elements; i++) {
6770 4d1cef84 Alex Bennée
        tcg_gen_shri_i64(tcg_rd, tcg_rn, i * esize);
6771 4d1cef84 Alex Bennée
        ext_and_shift_reg(tcg_rd, tcg_rd, size | (!is_u << 2), 0);
6772 4d1cef84 Alex Bennée
        tcg_gen_shli_i64(tcg_rd, tcg_rd, shift);
6773 4d1cef84 Alex Bennée
        write_vec_element(s, tcg_rd, rd, i, size + 1);
6774 4d1cef84 Alex Bennée
    }
6775 4d1cef84 Alex Bennée
}
6776 4d1cef84 Alex Bennée
6777 4d1cef84 Alex Bennée
6778 384b26fb Alex Bennée
/* C3.6.14 AdvSIMD shift by immediate
6779 384b26fb Alex Bennée
 *  31  30   29 28         23 22  19 18  16 15    11  10 9    5 4    0
6780 384b26fb Alex Bennée
 * +---+---+---+-------------+------+------+--------+---+------+------+
6781 384b26fb Alex Bennée
 * | 0 | Q | U | 0 1 1 1 1 0 | immh | immb | opcode | 1 |  Rn  |  Rd  |
6782 384b26fb Alex Bennée
 * +---+---+---+-------------+------+------+--------+---+------+------+
6783 384b26fb Alex Bennée
 */
6784 384b26fb Alex Bennée
static void disas_simd_shift_imm(DisasContext *s, uint32_t insn)
6785 384b26fb Alex Bennée
{
6786 4d1cef84 Alex Bennée
    int rd = extract32(insn, 0, 5);
6787 4d1cef84 Alex Bennée
    int rn = extract32(insn, 5, 5);
6788 4d1cef84 Alex Bennée
    int opcode = extract32(insn, 11, 5);
6789 4d1cef84 Alex Bennée
    int immb = extract32(insn, 16, 3);
6790 4d1cef84 Alex Bennée
    int immh = extract32(insn, 19, 4);
6791 4d1cef84 Alex Bennée
    bool is_u = extract32(insn, 29, 1);
6792 4d1cef84 Alex Bennée
    bool is_q = extract32(insn, 30, 1);
6793 4d1cef84 Alex Bennée
6794 4d1cef84 Alex Bennée
    switch (opcode) {
6795 4d1cef84 Alex Bennée
    case 0x00: /* SSHR / USHR */
6796 4d1cef84 Alex Bennée
    case 0x02: /* SSRA / USRA (accumulate) */
6797 4d1cef84 Alex Bennée
    case 0x04: /* SRSHR / URSHR (rounding) */
6798 4d1cef84 Alex Bennée
    case 0x06: /* SRSRA / URSRA (accum + rounding) */
6799 4d1cef84 Alex Bennée
        handle_vec_simd_shri(s, is_q, is_u, immh, immb, opcode, rn, rd);
6800 4d1cef84 Alex Bennée
        break;
6801 4d1cef84 Alex Bennée
    case 0x0a: /* SHL / SLI */
6802 4d1cef84 Alex Bennée
        handle_vec_simd_shli(s, is_q, is_u, immh, immb, opcode, rn, rd);
6803 4d1cef84 Alex Bennée
        break;
6804 4d1cef84 Alex Bennée
    case 0x14: /* SSHLL / USHLL */
6805 4d1cef84 Alex Bennée
        handle_vec_simd_wshli(s, is_q, is_u, immh, immb, opcode, rn, rd);
6806 4d1cef84 Alex Bennée
        break;
6807 4d1cef84 Alex Bennée
    default:
6808 4d1cef84 Alex Bennée
        /* We don't currently implement any of the Narrow or saturating shifts;
6809 4d1cef84 Alex Bennée
         * nor do we implement the fixed-point conversions in this
6810 4d1cef84 Alex Bennée
         * encoding group (SCVTF, FCVTZS, UCVTF, FCVTZU).
6811 4d1cef84 Alex Bennée
         */
6812 4d1cef84 Alex Bennée
        unsupported_encoding(s, insn);
6813 4d1cef84 Alex Bennée
        return;
6814 4d1cef84 Alex Bennée
    }
6815 384b26fb Alex Bennée
}
6816 384b26fb Alex Bennée
6817 a08582f4 Peter Maydell
static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size,
6818 a08582f4 Peter Maydell
                                int opcode, int rd, int rn, int rm)
6819 a08582f4 Peter Maydell
{
6820 a08582f4 Peter Maydell
    /* 3-reg-different widening insns: 64 x 64 -> 128 */
6821 a08582f4 Peter Maydell
    TCGv_i64 tcg_res[2];
6822 a08582f4 Peter Maydell
    int pass, accop;
6823 a08582f4 Peter Maydell
6824 a08582f4 Peter Maydell
    tcg_res[0] = tcg_temp_new_i64();
6825 a08582f4 Peter Maydell
    tcg_res[1] = tcg_temp_new_i64();
6826 a08582f4 Peter Maydell
6827 a08582f4 Peter Maydell
    /* Does this op do an adding accumulate, a subtracting accumulate,
6828 a08582f4 Peter Maydell
     * or no accumulate at all?
6829 a08582f4 Peter Maydell
     */
6830 a08582f4 Peter Maydell
    switch (opcode) {
6831 a08582f4 Peter Maydell
    case 5:
6832 a08582f4 Peter Maydell
    case 8:
6833 a08582f4 Peter Maydell
    case 9:
6834 a08582f4 Peter Maydell
        accop = 1;
6835 a08582f4 Peter Maydell
        break;
6836 a08582f4 Peter Maydell
    case 10:
6837 a08582f4 Peter Maydell
    case 11:
6838 a08582f4 Peter Maydell
        accop = -1;
6839 a08582f4 Peter Maydell
        break;
6840 a08582f4 Peter Maydell
    default:
6841 a08582f4 Peter Maydell
        accop = 0;
6842 a08582f4 Peter Maydell
        break;
6843 a08582f4 Peter Maydell
    }
6844 a08582f4 Peter Maydell
6845 a08582f4 Peter Maydell
    if (accop != 0) {
6846 a08582f4 Peter Maydell
        read_vec_element(s, tcg_res[0], rd, 0, MO_64);
6847 a08582f4 Peter Maydell
        read_vec_element(s, tcg_res[1], rd, 1, MO_64);
6848 a08582f4 Peter Maydell
    }
6849 a08582f4 Peter Maydell
6850 a08582f4 Peter Maydell
    /* size == 2 means two 32x32->64 operations; this is worth special
6851 a08582f4 Peter Maydell
     * casing because we can generally handle it inline.
6852 a08582f4 Peter Maydell
     */
6853 a08582f4 Peter Maydell
    if (size == 2) {
6854 a08582f4 Peter Maydell
        for (pass = 0; pass < 2; pass++) {
6855 a08582f4 Peter Maydell
            TCGv_i64 tcg_op1 = tcg_temp_new_i64();
6856 a08582f4 Peter Maydell
            TCGv_i64 tcg_op2 = tcg_temp_new_i64();
6857 a08582f4 Peter Maydell
            TCGv_i64 tcg_passres;
6858 a08582f4 Peter Maydell
            TCGMemOp memop = MO_32 | (is_u ? 0 : MO_SIGN);
6859 a08582f4 Peter Maydell
6860 a08582f4 Peter Maydell
            int elt = pass + is_q * 2;
6861 a08582f4 Peter Maydell
6862 a08582f4 Peter Maydell
            read_vec_element(s, tcg_op1, rn, elt, memop);
6863 a08582f4 Peter Maydell
            read_vec_element(s, tcg_op2, rm, elt, memop);
6864 a08582f4 Peter Maydell
6865 a08582f4 Peter Maydell
            if (accop == 0) {
6866 a08582f4 Peter Maydell
                tcg_passres = tcg_res[pass];
6867 a08582f4 Peter Maydell
            } else {
6868 a08582f4 Peter Maydell
                tcg_passres = tcg_temp_new_i64();
6869 a08582f4 Peter Maydell
            }
6870 a08582f4 Peter Maydell
6871 a08582f4 Peter Maydell
            switch (opcode) {
6872 0ae39320 Peter Maydell
            case 5: /* SABAL, SABAL2, UABAL, UABAL2 */
6873 0ae39320 Peter Maydell
            case 7: /* SABDL, SABDL2, UABDL, UABDL2 */
6874 0ae39320 Peter Maydell
            {
6875 0ae39320 Peter Maydell
                TCGv_i64 tcg_tmp1 = tcg_temp_new_i64();
6876 0ae39320 Peter Maydell
                TCGv_i64 tcg_tmp2 = tcg_temp_new_i64();
6877 0ae39320 Peter Maydell
6878 0ae39320 Peter Maydell
                tcg_gen_sub_i64(tcg_tmp1, tcg_op1, tcg_op2);
6879 0ae39320 Peter Maydell
                tcg_gen_sub_i64(tcg_tmp2, tcg_op2, tcg_op1);
6880 0ae39320 Peter Maydell
                tcg_gen_movcond_i64(is_u ? TCG_COND_GEU : TCG_COND_GE,
6881 0ae39320 Peter Maydell
                                    tcg_passres,
6882 0ae39320 Peter Maydell
                                    tcg_op1, tcg_op2, tcg_tmp1, tcg_tmp2);
6883 0ae39320 Peter Maydell
                tcg_temp_free_i64(tcg_tmp1);
6884 0ae39320 Peter Maydell
                tcg_temp_free_i64(tcg_tmp2);
6885 0ae39320 Peter Maydell
                break;
6886 0ae39320 Peter Maydell
            }
6887 a08582f4 Peter Maydell
            case 8: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
6888 a08582f4 Peter Maydell
            case 10: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
6889 a08582f4 Peter Maydell
            case 12: /* UMULL, UMULL2, SMULL, SMULL2 */
6890 a08582f4 Peter Maydell
                tcg_gen_mul_i64(tcg_passres, tcg_op1, tcg_op2);
6891 a08582f4 Peter Maydell
                break;
6892 a08582f4 Peter Maydell
            default:
6893 a08582f4 Peter Maydell
                g_assert_not_reached();
6894 a08582f4 Peter Maydell
            }
6895 a08582f4 Peter Maydell
6896 a08582f4 Peter Maydell
            if (accop > 0) {
6897 a08582f4 Peter Maydell
                tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
6898 a08582f4 Peter Maydell
                tcg_temp_free_i64(tcg_passres);
6899 a08582f4 Peter Maydell
            } else if (accop < 0) {
6900 a08582f4 Peter Maydell
                tcg_gen_sub_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
6901 a08582f4 Peter Maydell
                tcg_temp_free_i64(tcg_passres);
6902 a08582f4 Peter Maydell
            }
6903 a08582f4 Peter Maydell
6904 a08582f4 Peter Maydell
            tcg_temp_free_i64(tcg_op1);
6905 a08582f4 Peter Maydell
            tcg_temp_free_i64(tcg_op2);
6906 a08582f4 Peter Maydell
        }
6907 a08582f4 Peter Maydell
    } else {
6908 a08582f4 Peter Maydell
        /* size 0 or 1, generally helper functions */
6909 a08582f4 Peter Maydell
        for (pass = 0; pass < 2; pass++) {
6910 a08582f4 Peter Maydell
            TCGv_i32 tcg_op1 = tcg_temp_new_i32();
6911 a08582f4 Peter Maydell
            TCGv_i32 tcg_op2 = tcg_temp_new_i32();
6912 a08582f4 Peter Maydell
            TCGv_i64 tcg_passres;
6913 a08582f4 Peter Maydell
            int elt = pass + is_q * 2;
6914 a08582f4 Peter Maydell
6915 a08582f4 Peter Maydell
            read_vec_element_i32(s, tcg_op1, rn, elt, MO_32);
6916 a08582f4 Peter Maydell
            read_vec_element_i32(s, tcg_op2, rm, elt, MO_32);
6917 a08582f4 Peter Maydell
6918 a08582f4 Peter Maydell
            if (accop == 0) {
6919 a08582f4 Peter Maydell
                tcg_passres = tcg_res[pass];
6920 a08582f4 Peter Maydell
            } else {
6921 a08582f4 Peter Maydell
                tcg_passres = tcg_temp_new_i64();
6922 a08582f4 Peter Maydell
            }
6923 a08582f4 Peter Maydell
6924 a08582f4 Peter Maydell
            switch (opcode) {
6925 0ae39320 Peter Maydell
            case 5: /* SABAL, SABAL2, UABAL, UABAL2 */
6926 0ae39320 Peter Maydell
            case 7: /* SABDL, SABDL2, UABDL, UABDL2 */
6927 0ae39320 Peter Maydell
                if (size == 0) {
6928 0ae39320 Peter Maydell
                    if (is_u) {
6929 0ae39320 Peter Maydell
                        gen_helper_neon_abdl_u16(tcg_passres, tcg_op1, tcg_op2);
6930 0ae39320 Peter Maydell
                    } else {
6931 0ae39320 Peter Maydell
                        gen_helper_neon_abdl_s16(tcg_passres, tcg_op1, tcg_op2);
6932 0ae39320 Peter Maydell
                    }
6933 0ae39320 Peter Maydell
                } else {
6934 0ae39320 Peter Maydell
                    if (is_u) {
6935 0ae39320 Peter Maydell
                        gen_helper_neon_abdl_u32(tcg_passres, tcg_op1, tcg_op2);
6936 0ae39320 Peter Maydell
                    } else {
6937 0ae39320 Peter Maydell
                        gen_helper_neon_abdl_s32(tcg_passres, tcg_op1, tcg_op2);
6938 0ae39320 Peter Maydell
                    }
6939 0ae39320 Peter Maydell
                }
6940 0ae39320 Peter Maydell
                break;
6941 a08582f4 Peter Maydell
            case 8: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
6942 a08582f4 Peter Maydell
            case 10: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
6943 a08582f4 Peter Maydell
            case 12: /* UMULL, UMULL2, SMULL, SMULL2 */
6944 a08582f4 Peter Maydell
                if (size == 0) {
6945 a08582f4 Peter Maydell
                    if (is_u) {
6946 a08582f4 Peter Maydell
                        gen_helper_neon_mull_u8(tcg_passres, tcg_op1, tcg_op2);
6947 a08582f4 Peter Maydell
                    } else {
6948 a08582f4 Peter Maydell
                        gen_helper_neon_mull_s8(tcg_passres, tcg_op1, tcg_op2);
6949 a08582f4 Peter Maydell
                    }
6950 a08582f4 Peter Maydell
                } else {
6951 a08582f4 Peter Maydell
                    if (is_u) {
6952 a08582f4 Peter Maydell
                        gen_helper_neon_mull_u16(tcg_passres, tcg_op1, tcg_op2);
6953 a08582f4 Peter Maydell
                    } else {
6954 a08582f4 Peter Maydell
                        gen_helper_neon_mull_s16(tcg_passres, tcg_op1, tcg_op2);
6955 a08582f4 Peter Maydell
                    }
6956 a08582f4 Peter Maydell
                }
6957 a08582f4 Peter Maydell
                break;
6958 a08582f4 Peter Maydell
            default:
6959 a08582f4 Peter Maydell
                g_assert_not_reached();
6960 a08582f4 Peter Maydell
            }
6961 a08582f4 Peter Maydell
            tcg_temp_free_i32(tcg_op1);
6962 a08582f4 Peter Maydell
            tcg_temp_free_i32(tcg_op2);
6963 a08582f4 Peter Maydell
6964 a08582f4 Peter Maydell
            if (accop > 0) {
6965 a08582f4 Peter Maydell
                if (size == 0) {
6966 a08582f4 Peter Maydell
                    gen_helper_neon_addl_u16(tcg_res[pass], tcg_res[pass],
6967 a08582f4 Peter Maydell
                                             tcg_passres);
6968 a08582f4 Peter Maydell
                } else {
6969 a08582f4 Peter Maydell
                    gen_helper_neon_addl_u32(tcg_res[pass], tcg_res[pass],
6970 a08582f4 Peter Maydell
                                             tcg_passres);
6971 a08582f4 Peter Maydell
                }
6972 a08582f4 Peter Maydell
                tcg_temp_free_i64(tcg_passres);
6973 a08582f4 Peter Maydell
            } else if (accop < 0) {
6974 a08582f4 Peter Maydell
                if (size == 0) {
6975 a08582f4 Peter Maydell
                    gen_helper_neon_subl_u16(tcg_res[pass], tcg_res[pass],
6976 a08582f4 Peter Maydell
                                             tcg_passres);
6977 a08582f4 Peter Maydell
                } else {
6978 a08582f4 Peter Maydell
                    gen_helper_neon_subl_u32(tcg_res[pass], tcg_res[pass],
6979 a08582f4 Peter Maydell
                                             tcg_passres);
6980 a08582f4 Peter Maydell
                }
6981 a08582f4 Peter Maydell
                tcg_temp_free_i64(tcg_passres);
6982 a08582f4 Peter Maydell
            }
6983 a08582f4 Peter Maydell
        }
6984 a08582f4 Peter Maydell
    }
6985 a08582f4 Peter Maydell
6986 a08582f4 Peter Maydell
    write_vec_element(s, tcg_res[0], rd, 0, MO_64);
6987 a08582f4 Peter Maydell
    write_vec_element(s, tcg_res[1], rd, 1, MO_64);
6988 a08582f4 Peter Maydell
    tcg_temp_free_i64(tcg_res[0]);
6989 a08582f4 Peter Maydell
    tcg_temp_free_i64(tcg_res[1]);
6990 a08582f4 Peter Maydell
}
6991 a08582f4 Peter Maydell
6992 384b26fb Alex Bennée
/* C3.6.15 AdvSIMD three different
6993 384b26fb Alex Bennée
 *   31  30  29 28       24 23  22  21 20  16 15    12 11 10 9    5 4    0
6994 384b26fb Alex Bennée
 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
6995 384b26fb Alex Bennée
 * | 0 | Q | U | 0 1 1 1 0 | size | 1 |  Rm  | opcode | 0 0 |  Rn  |  Rd  |
6996 384b26fb Alex Bennée
 * +---+---+---+-----------+------+---+------+--------+-----+------+------+
6997 384b26fb Alex Bennée
 */
6998 384b26fb Alex Bennée
static void disas_simd_three_reg_diff(DisasContext *s, uint32_t insn)
6999 384b26fb Alex Bennée
{
7000 a08582f4 Peter Maydell
    /* Instructions in this group fall into three basic classes
7001 a08582f4 Peter Maydell
     * (in each case with the operation working on each element in
7002 a08582f4 Peter Maydell
     * the input vectors):
7003 a08582f4 Peter Maydell
     * (1) widening 64 x 64 -> 128 (with possibly Vd as an extra
7004 a08582f4 Peter Maydell
     *     128 bit input)
7005 a08582f4 Peter Maydell
     * (2) wide 64 x 128 -> 128
7006 a08582f4 Peter Maydell
     * (3) narrowing 128 x 128 -> 64
7007 a08582f4 Peter Maydell
     * Here we do initial decode, catch unallocated cases and
7008 a08582f4 Peter Maydell
     * dispatch to separate functions for each class.
7009 a08582f4 Peter Maydell
     */
7010 a08582f4 Peter Maydell
    int is_q = extract32(insn, 30, 1);
7011 a08582f4 Peter Maydell
    int is_u = extract32(insn, 29, 1);
7012 a08582f4 Peter Maydell
    int size = extract32(insn, 22, 2);
7013 a08582f4 Peter Maydell
    int opcode = extract32(insn, 12, 4);
7014 a08582f4 Peter Maydell
    int rm = extract32(insn, 16, 5);
7015 a08582f4 Peter Maydell
    int rn = extract32(insn, 5, 5);
7016 a08582f4 Peter Maydell
    int rd = extract32(insn, 0, 5);
7017 a08582f4 Peter Maydell
7018 a08582f4 Peter Maydell
    switch (opcode) {
7019 a08582f4 Peter Maydell
    case 1: /* SADDW, SADDW2, UADDW, UADDW2 */
7020 a08582f4 Peter Maydell
    case 3: /* SSUBW, SSUBW2, USUBW, USUBW2 */
7021 a08582f4 Peter Maydell
        /* 64 x 128 -> 128 */
7022 a08582f4 Peter Maydell
        unsupported_encoding(s, insn);
7023 a08582f4 Peter Maydell
        break;
7024 a08582f4 Peter Maydell
    case 4: /* ADDHN, ADDHN2, RADDHN, RADDHN2 */
7025 a08582f4 Peter Maydell
    case 6: /* SUBHN, SUBHN2, RSUBHN, RSUBHN2 */
7026 a08582f4 Peter Maydell
        /* 128 x 128 -> 64 */
7027 a08582f4 Peter Maydell
        unsupported_encoding(s, insn);
7028 a08582f4 Peter Maydell
        break;
7029 a08582f4 Peter Maydell
    case 9:
7030 a08582f4 Peter Maydell
    case 11:
7031 a08582f4 Peter Maydell
    case 13:
7032 a08582f4 Peter Maydell
    case 14:
7033 a08582f4 Peter Maydell
        if (is_u) {
7034 a08582f4 Peter Maydell
            unallocated_encoding(s);
7035 a08582f4 Peter Maydell
            return;
7036 a08582f4 Peter Maydell
        }
7037 a08582f4 Peter Maydell
        /* fall through */
7038 a08582f4 Peter Maydell
    case 0:
7039 a08582f4 Peter Maydell
    case 2:
7040 a08582f4 Peter Maydell
        unsupported_encoding(s, insn);
7041 a08582f4 Peter Maydell
        break;
7042 0ae39320 Peter Maydell
    case 5:
7043 0ae39320 Peter Maydell
    case 7:
7044 a08582f4 Peter Maydell
    case 8:
7045 a08582f4 Peter Maydell
    case 10:
7046 a08582f4 Peter Maydell
    case 12:
7047 a08582f4 Peter Maydell
        /* 64 x 64 -> 128 */
7048 a08582f4 Peter Maydell
        if (size == 3) {
7049 a08582f4 Peter Maydell
            unallocated_encoding(s);
7050 a08582f4 Peter Maydell
            return;
7051 a08582f4 Peter Maydell
        }
7052 a08582f4 Peter Maydell
        handle_3rd_widening(s, is_q, is_u, size, opcode, rd, rn, rm);
7053 a08582f4 Peter Maydell
        break;
7054 a08582f4 Peter Maydell
    default:
7055 a08582f4 Peter Maydell
        /* opcode 15 not allocated */
7056 a08582f4 Peter Maydell
        unallocated_encoding(s);
7057 a08582f4 Peter Maydell
        break;
7058 a08582f4 Peter Maydell
    }
7059 384b26fb Alex Bennée
}
7060 384b26fb Alex Bennée
7061 e1cea114 Peter Maydell
/* Logic op (opcode == 3) subgroup of C3.6.16. */
7062 e1cea114 Peter Maydell
static void disas_simd_3same_logic(DisasContext *s, uint32_t insn)
7063 e1cea114 Peter Maydell
{
7064 956d272e Peter Maydell
    int rd = extract32(insn, 0, 5);
7065 956d272e Peter Maydell
    int rn = extract32(insn, 5, 5);
7066 956d272e Peter Maydell
    int rm = extract32(insn, 16, 5);
7067 956d272e Peter Maydell
    int size = extract32(insn, 22, 2);
7068 956d272e Peter Maydell
    bool is_u = extract32(insn, 29, 1);
7069 956d272e Peter Maydell
    bool is_q = extract32(insn, 30, 1);
7070 956d272e Peter Maydell
    TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7071 956d272e Peter Maydell
    TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7072 956d272e Peter Maydell
    TCGv_i64 tcg_res[2];
7073 956d272e Peter Maydell
    int pass;
7074 956d272e Peter Maydell
7075 956d272e Peter Maydell
    tcg_res[0] = tcg_temp_new_i64();
7076 956d272e Peter Maydell
    tcg_res[1] = tcg_temp_new_i64();
7077 956d272e Peter Maydell
7078 956d272e Peter Maydell
    for (pass = 0; pass < (is_q ? 2 : 1); pass++) {
7079 956d272e Peter Maydell
        read_vec_element(s, tcg_op1, rn, pass, MO_64);
7080 956d272e Peter Maydell
        read_vec_element(s, tcg_op2, rm, pass, MO_64);
7081 956d272e Peter Maydell
7082 956d272e Peter Maydell
        if (!is_u) {
7083 956d272e Peter Maydell
            switch (size) {
7084 956d272e Peter Maydell
            case 0: /* AND */
7085 956d272e Peter Maydell
                tcg_gen_and_i64(tcg_res[pass], tcg_op1, tcg_op2);
7086 956d272e Peter Maydell
                break;
7087 956d272e Peter Maydell
            case 1: /* BIC */
7088 956d272e Peter Maydell
                tcg_gen_andc_i64(tcg_res[pass], tcg_op1, tcg_op2);
7089 956d272e Peter Maydell
                break;
7090 956d272e Peter Maydell
            case 2: /* ORR */
7091 956d272e Peter Maydell
                tcg_gen_or_i64(tcg_res[pass], tcg_op1, tcg_op2);
7092 956d272e Peter Maydell
                break;
7093 956d272e Peter Maydell
            case 3: /* ORN */
7094 956d272e Peter Maydell
                tcg_gen_orc_i64(tcg_res[pass], tcg_op1, tcg_op2);
7095 956d272e Peter Maydell
                break;
7096 956d272e Peter Maydell
            }
7097 956d272e Peter Maydell
        } else {
7098 956d272e Peter Maydell
            if (size != 0) {
7099 956d272e Peter Maydell
                /* B* ops need res loaded to operate on */
7100 956d272e Peter Maydell
                read_vec_element(s, tcg_res[pass], rd, pass, MO_64);
7101 956d272e Peter Maydell
            }
7102 956d272e Peter Maydell
7103 956d272e Peter Maydell
            switch (size) {
7104 956d272e Peter Maydell
            case 0: /* EOR */
7105 956d272e Peter Maydell
                tcg_gen_xor_i64(tcg_res[pass], tcg_op1, tcg_op2);
7106 956d272e Peter Maydell
                break;
7107 956d272e Peter Maydell
            case 1: /* BSL bitwise select */
7108 956d272e Peter Maydell
                tcg_gen_xor_i64(tcg_op1, tcg_op1, tcg_op2);
7109 956d272e Peter Maydell
                tcg_gen_and_i64(tcg_op1, tcg_op1, tcg_res[pass]);
7110 956d272e Peter Maydell
                tcg_gen_xor_i64(tcg_res[pass], tcg_op2, tcg_op1);
7111 956d272e Peter Maydell
                break;
7112 956d272e Peter Maydell
            case 2: /* BIT, bitwise insert if true */
7113 956d272e Peter Maydell
                tcg_gen_xor_i64(tcg_op1, tcg_op1, tcg_res[pass]);
7114 956d272e Peter Maydell
                tcg_gen_and_i64(tcg_op1, tcg_op1, tcg_op2);
7115 956d272e Peter Maydell
                tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
7116 956d272e Peter Maydell
                break;
7117 956d272e Peter Maydell
            case 3: /* BIF, bitwise insert if false */
7118 956d272e Peter Maydell
                tcg_gen_xor_i64(tcg_op1, tcg_op1, tcg_res[pass]);
7119 956d272e Peter Maydell
                tcg_gen_andc_i64(tcg_op1, tcg_op1, tcg_op2);
7120 956d272e Peter Maydell
                tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
7121 956d272e Peter Maydell
                break;
7122 956d272e Peter Maydell
            }
7123 956d272e Peter Maydell
        }
7124 956d272e Peter Maydell
    }
7125 956d272e Peter Maydell
7126 956d272e Peter Maydell
    write_vec_element(s, tcg_res[0], rd, 0, MO_64);
7127 956d272e Peter Maydell
    if (!is_q) {
7128 956d272e Peter Maydell
        tcg_gen_movi_i64(tcg_res[1], 0);
7129 956d272e Peter Maydell
    }
7130 956d272e Peter Maydell
    write_vec_element(s, tcg_res[1], rd, 1, MO_64);
7131 956d272e Peter Maydell
7132 956d272e Peter Maydell
    tcg_temp_free_i64(tcg_op1);
7133 956d272e Peter Maydell
    tcg_temp_free_i64(tcg_op2);
7134 956d272e Peter Maydell
    tcg_temp_free_i64(tcg_res[0]);
7135 956d272e Peter Maydell
    tcg_temp_free_i64(tcg_res[1]);
7136 e1cea114 Peter Maydell
}
7137 e1cea114 Peter Maydell
7138 8b12a0cf Peter Maydell
/* Helper functions for 32 bit comparisons */
7139 8b12a0cf Peter Maydell
static void gen_max_s32(TCGv_i32 res, TCGv_i32 op1, TCGv_i32 op2)
7140 8b12a0cf Peter Maydell
{
7141 8b12a0cf Peter Maydell
    tcg_gen_movcond_i32(TCG_COND_GE, res, op1, op2, op1, op2);
7142 8b12a0cf Peter Maydell
}
7143 8b12a0cf Peter Maydell
7144 8b12a0cf Peter Maydell
static void gen_max_u32(TCGv_i32 res, TCGv_i32 op1, TCGv_i32 op2)
7145 8b12a0cf Peter Maydell
{
7146 8b12a0cf Peter Maydell
    tcg_gen_movcond_i32(TCG_COND_GEU, res, op1, op2, op1, op2);
7147 8b12a0cf Peter Maydell
}
7148 8b12a0cf Peter Maydell
7149 8b12a0cf Peter Maydell
static void gen_min_s32(TCGv_i32 res, TCGv_i32 op1, TCGv_i32 op2)
7150 8b12a0cf Peter Maydell
{
7151 8b12a0cf Peter Maydell
    tcg_gen_movcond_i32(TCG_COND_LE, res, op1, op2, op1, op2);
7152 8b12a0cf Peter Maydell
}
7153 8b12a0cf Peter Maydell
7154 8b12a0cf Peter Maydell
static void gen_min_u32(TCGv_i32 res, TCGv_i32 op1, TCGv_i32 op2)
7155 8b12a0cf Peter Maydell
{
7156 8b12a0cf Peter Maydell
    tcg_gen_movcond_i32(TCG_COND_LEU, res, op1, op2, op1, op2);
7157 8b12a0cf Peter Maydell
}
7158 8b12a0cf Peter Maydell
7159 bc242f9b Alex Bennée
/* Pairwise op subgroup of C3.6.16.
7160 bc242f9b Alex Bennée
 *
7161 bc242f9b Alex Bennée
 * This is called directly or via the handle_3same_float for float pairwise
7162 bc242f9b Alex Bennée
 * operations where the opcode and size are calculated differently.
7163 bc242f9b Alex Bennée
 */
7164 bc242f9b Alex Bennée
static void handle_simd_3same_pair(DisasContext *s, int is_q, int u, int opcode,
7165 bc242f9b Alex Bennée
                                   int size, int rn, int rm, int rd)
7166 e1cea114 Peter Maydell
{
7167 bc242f9b Alex Bennée
    TCGv_ptr fpst;
7168 0173a005 Peter Maydell
    int pass;
7169 0173a005 Peter Maydell
7170 bc242f9b Alex Bennée
    /* Floating point operations need fpst */
7171 bc242f9b Alex Bennée
    if (opcode >= 0x58) {
7172 bc242f9b Alex Bennée
        fpst = get_fpstatus_ptr();
7173 bc242f9b Alex Bennée
    } else {
7174 bc242f9b Alex Bennée
        TCGV_UNUSED_PTR(fpst);
7175 0173a005 Peter Maydell
    }
7176 0173a005 Peter Maydell
7177 0173a005 Peter Maydell
    /* These operations work on the concatenated rm:rn, with each pair of
7178 0173a005 Peter Maydell
     * adjacent elements being operated on to produce an element in the result.
7179 0173a005 Peter Maydell
     */
7180 0173a005 Peter Maydell
    if (size == 3) {
7181 0173a005 Peter Maydell
        TCGv_i64 tcg_res[2];
7182 0173a005 Peter Maydell
7183 0173a005 Peter Maydell
        for (pass = 0; pass < 2; pass++) {
7184 0173a005 Peter Maydell
            TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7185 0173a005 Peter Maydell
            TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7186 0173a005 Peter Maydell
            int passreg = (pass == 0) ? rn : rm;
7187 0173a005 Peter Maydell
7188 0173a005 Peter Maydell
            read_vec_element(s, tcg_op1, passreg, 0, MO_64);
7189 0173a005 Peter Maydell
            read_vec_element(s, tcg_op2, passreg, 1, MO_64);
7190 0173a005 Peter Maydell
            tcg_res[pass] = tcg_temp_new_i64();
7191 0173a005 Peter Maydell
7192 bc242f9b Alex Bennée
            switch (opcode) {
7193 bc242f9b Alex Bennée
            case 0x17: /* ADDP */
7194 bc242f9b Alex Bennée
                tcg_gen_add_i64(tcg_res[pass], tcg_op1, tcg_op2);
7195 bc242f9b Alex Bennée
                break;
7196 bc242f9b Alex Bennée
            case 0x58: /* FMAXNMP */
7197 bc242f9b Alex Bennée
                gen_helper_vfp_maxnumd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7198 bc242f9b Alex Bennée
                break;
7199 bc242f9b Alex Bennée
            case 0x5a: /* FADDP */
7200 bc242f9b Alex Bennée
                gen_helper_vfp_addd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7201 bc242f9b Alex Bennée
                break;
7202 bc242f9b Alex Bennée
            case 0x5e: /* FMAXP */
7203 bc242f9b Alex Bennée
                gen_helper_vfp_maxd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7204 bc242f9b Alex Bennée
                break;
7205 bc242f9b Alex Bennée
            case 0x78: /* FMINNMP */
7206 bc242f9b Alex Bennée
                gen_helper_vfp_minnumd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7207 bc242f9b Alex Bennée
                break;
7208 bc242f9b Alex Bennée
            case 0x7e: /* FMINP */
7209 bc242f9b Alex Bennée
                gen_helper_vfp_mind(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7210 bc242f9b Alex Bennée
                break;
7211 bc242f9b Alex Bennée
            default:
7212 bc242f9b Alex Bennée
                g_assert_not_reached();
7213 bc242f9b Alex Bennée
            }
7214 0173a005 Peter Maydell
7215 0173a005 Peter Maydell
            tcg_temp_free_i64(tcg_op1);
7216 0173a005 Peter Maydell
            tcg_temp_free_i64(tcg_op2);
7217 0173a005 Peter Maydell
        }
7218 0173a005 Peter Maydell
7219 0173a005 Peter Maydell
        for (pass = 0; pass < 2; pass++) {
7220 0173a005 Peter Maydell
            write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
7221 0173a005 Peter Maydell
            tcg_temp_free_i64(tcg_res[pass]);
7222 0173a005 Peter Maydell
        }
7223 0173a005 Peter Maydell
    } else {
7224 0173a005 Peter Maydell
        int maxpass = is_q ? 4 : 2;
7225 0173a005 Peter Maydell
        TCGv_i32 tcg_res[4];
7226 0173a005 Peter Maydell
7227 0173a005 Peter Maydell
        for (pass = 0; pass < maxpass; pass++) {
7228 0173a005 Peter Maydell
            TCGv_i32 tcg_op1 = tcg_temp_new_i32();
7229 0173a005 Peter Maydell
            TCGv_i32 tcg_op2 = tcg_temp_new_i32();
7230 bc242f9b Alex Bennée
            NeonGenTwoOpFn *genfn = NULL;
7231 0173a005 Peter Maydell
            int passreg = pass < (maxpass / 2) ? rn : rm;
7232 0173a005 Peter Maydell
            int passelt = (is_q && (pass & 1)) ? 2 : 0;
7233 0173a005 Peter Maydell
7234 0173a005 Peter Maydell
            read_vec_element_i32(s, tcg_op1, passreg, passelt, MO_32);
7235 0173a005 Peter Maydell
            read_vec_element_i32(s, tcg_op2, passreg, passelt + 1, MO_32);
7236 0173a005 Peter Maydell
            tcg_res[pass] = tcg_temp_new_i32();
7237 0173a005 Peter Maydell
7238 0173a005 Peter Maydell
            switch (opcode) {
7239 0173a005 Peter Maydell
            case 0x17: /* ADDP */
7240 0173a005 Peter Maydell
            {
7241 0173a005 Peter Maydell
                static NeonGenTwoOpFn * const fns[3] = {
7242 0173a005 Peter Maydell
                    gen_helper_neon_padd_u8,
7243 0173a005 Peter Maydell
                    gen_helper_neon_padd_u16,
7244 0173a005 Peter Maydell
                    tcg_gen_add_i32,
7245 0173a005 Peter Maydell
                };
7246 0173a005 Peter Maydell
                genfn = fns[size];
7247 0173a005 Peter Maydell
                break;
7248 0173a005 Peter Maydell
            }
7249 0173a005 Peter Maydell
            case 0x14: /* SMAXP, UMAXP */
7250 0173a005 Peter Maydell
            {
7251 0173a005 Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7252 0173a005 Peter Maydell
                    { gen_helper_neon_pmax_s8, gen_helper_neon_pmax_u8 },
7253 0173a005 Peter Maydell
                    { gen_helper_neon_pmax_s16, gen_helper_neon_pmax_u16 },
7254 0173a005 Peter Maydell
                    { gen_max_s32, gen_max_u32 },
7255 0173a005 Peter Maydell
                };
7256 0173a005 Peter Maydell
                genfn = fns[size][u];
7257 0173a005 Peter Maydell
                break;
7258 0173a005 Peter Maydell
            }
7259 0173a005 Peter Maydell
            case 0x15: /* SMINP, UMINP */
7260 0173a005 Peter Maydell
            {
7261 0173a005 Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7262 0173a005 Peter Maydell
                    { gen_helper_neon_pmin_s8, gen_helper_neon_pmin_u8 },
7263 0173a005 Peter Maydell
                    { gen_helper_neon_pmin_s16, gen_helper_neon_pmin_u16 },
7264 0173a005 Peter Maydell
                    { gen_min_s32, gen_min_u32 },
7265 0173a005 Peter Maydell
                };
7266 0173a005 Peter Maydell
                genfn = fns[size][u];
7267 0173a005 Peter Maydell
                break;
7268 0173a005 Peter Maydell
            }
7269 bc242f9b Alex Bennée
            /* The FP operations are all on single floats (32 bit) */
7270 bc242f9b Alex Bennée
            case 0x58: /* FMAXNMP */
7271 bc242f9b Alex Bennée
                gen_helper_vfp_maxnums(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7272 bc242f9b Alex Bennée
                break;
7273 bc242f9b Alex Bennée
            case 0x5a: /* FADDP */
7274 bc242f9b Alex Bennée
                gen_helper_vfp_adds(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7275 bc242f9b Alex Bennée
                break;
7276 bc242f9b Alex Bennée
            case 0x5e: /* FMAXP */
7277 bc242f9b Alex Bennée
                gen_helper_vfp_maxs(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7278 bc242f9b Alex Bennée
                break;
7279 bc242f9b Alex Bennée
            case 0x78: /* FMINNMP */
7280 bc242f9b Alex Bennée
                gen_helper_vfp_minnums(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7281 bc242f9b Alex Bennée
                break;
7282 bc242f9b Alex Bennée
            case 0x7e: /* FMINP */
7283 bc242f9b Alex Bennée
                gen_helper_vfp_mins(tcg_res[pass], tcg_op1, tcg_op2, fpst);
7284 bc242f9b Alex Bennée
                break;
7285 0173a005 Peter Maydell
            default:
7286 0173a005 Peter Maydell
                g_assert_not_reached();
7287 0173a005 Peter Maydell
            }
7288 0173a005 Peter Maydell
7289 bc242f9b Alex Bennée
            /* FP ops called directly, otherwise call now */
7290 bc242f9b Alex Bennée
            if (genfn) {
7291 bc242f9b Alex Bennée
                genfn(tcg_res[pass], tcg_op1, tcg_op2);
7292 bc242f9b Alex Bennée
            }
7293 0173a005 Peter Maydell
7294 0173a005 Peter Maydell
            tcg_temp_free_i32(tcg_op1);
7295 0173a005 Peter Maydell
            tcg_temp_free_i32(tcg_op2);
7296 0173a005 Peter Maydell
        }
7297 0173a005 Peter Maydell
7298 0173a005 Peter Maydell
        for (pass = 0; pass < maxpass; pass++) {
7299 0173a005 Peter Maydell
            write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_32);
7300 0173a005 Peter Maydell
            tcg_temp_free_i32(tcg_res[pass]);
7301 0173a005 Peter Maydell
        }
7302 0173a005 Peter Maydell
        if (!is_q) {
7303 0173a005 Peter Maydell
            clear_vec_high(s, rd);
7304 0173a005 Peter Maydell
        }
7305 0173a005 Peter Maydell
    }
7306 bc242f9b Alex Bennée
7307 bc242f9b Alex Bennée
    if (!TCGV_IS_UNUSED_PTR(fpst)) {
7308 bc242f9b Alex Bennée
        tcg_temp_free_ptr(fpst);
7309 bc242f9b Alex Bennée
    }
7310 e1cea114 Peter Maydell
}
7311 e1cea114 Peter Maydell
7312 e1cea114 Peter Maydell
/* Floating point op subgroup of C3.6.16. */
7313 e1cea114 Peter Maydell
static void disas_simd_3same_float(DisasContext *s, uint32_t insn)
7314 e1cea114 Peter Maydell
{
7315 845ea09a Peter Maydell
    /* For floating point ops, the U, size[1] and opcode bits
7316 845ea09a Peter Maydell
     * together indicate the operation. size[0] indicates single
7317 845ea09a Peter Maydell
     * or double.
7318 845ea09a Peter Maydell
     */
7319 845ea09a Peter Maydell
    int fpopcode = extract32(insn, 11, 5)
7320 845ea09a Peter Maydell
        | (extract32(insn, 23, 1) << 5)
7321 845ea09a Peter Maydell
        | (extract32(insn, 29, 1) << 6);
7322 845ea09a Peter Maydell
    int is_q = extract32(insn, 30, 1);
7323 845ea09a Peter Maydell
    int size = extract32(insn, 22, 1);
7324 845ea09a Peter Maydell
    int rm = extract32(insn, 16, 5);
7325 845ea09a Peter Maydell
    int rn = extract32(insn, 5, 5);
7326 845ea09a Peter Maydell
    int rd = extract32(insn, 0, 5);
7327 845ea09a Peter Maydell
7328 845ea09a Peter Maydell
    int datasize = is_q ? 128 : 64;
7329 845ea09a Peter Maydell
    int esize = 32 << size;
7330 845ea09a Peter Maydell
    int elements = datasize / esize;
7331 845ea09a Peter Maydell
7332 845ea09a Peter Maydell
    if (size == 1 && !is_q) {
7333 845ea09a Peter Maydell
        unallocated_encoding(s);
7334 845ea09a Peter Maydell
        return;
7335 845ea09a Peter Maydell
    }
7336 845ea09a Peter Maydell
7337 845ea09a Peter Maydell
    switch (fpopcode) {
7338 845ea09a Peter Maydell
    case 0x58: /* FMAXNMP */
7339 845ea09a Peter Maydell
    case 0x5a: /* FADDP */
7340 845ea09a Peter Maydell
    case 0x5e: /* FMAXP */
7341 845ea09a Peter Maydell
    case 0x78: /* FMINNMP */
7342 845ea09a Peter Maydell
    case 0x7e: /* FMINP */
7343 bc242f9b Alex Bennée
        if (size && !is_q) {
7344 bc242f9b Alex Bennée
            unallocated_encoding(s);
7345 bc242f9b Alex Bennée
            return;
7346 bc242f9b Alex Bennée
        }
7347 bc242f9b Alex Bennée
        handle_simd_3same_pair(s, is_q, 0, fpopcode, size ? MO_64 : MO_32,
7348 bc242f9b Alex Bennée
                               rn, rm, rd);
7349 845ea09a Peter Maydell
        return;
7350 845ea09a Peter Maydell
    case 0x1b: /* FMULX */
7351 845ea09a Peter Maydell
    case 0x1f: /* FRECPS */
7352 845ea09a Peter Maydell
    case 0x3f: /* FRSQRTS */
7353 845ea09a Peter Maydell
    case 0x5d: /* FACGE */
7354 845ea09a Peter Maydell
    case 0x7d: /* FACGT */
7355 845ea09a Peter Maydell
    case 0x19: /* FMLA */
7356 845ea09a Peter Maydell
    case 0x39: /* FMLS */
7357 845ea09a Peter Maydell
    case 0x18: /* FMAXNM */
7358 845ea09a Peter Maydell
    case 0x1a: /* FADD */
7359 8908f4d1 Alex Bennée
    case 0x1c: /* FCMEQ */
7360 845ea09a Peter Maydell
    case 0x1e: /* FMAX */
7361 845ea09a Peter Maydell
    case 0x38: /* FMINNM */
7362 845ea09a Peter Maydell
    case 0x3a: /* FSUB */
7363 845ea09a Peter Maydell
    case 0x3e: /* FMIN */
7364 845ea09a Peter Maydell
    case 0x5b: /* FMUL */
7365 8908f4d1 Alex Bennée
    case 0x5c: /* FCMGE */
7366 845ea09a Peter Maydell
    case 0x5f: /* FDIV */
7367 845ea09a Peter Maydell
    case 0x7a: /* FABD */
7368 8908f4d1 Alex Bennée
    case 0x7c: /* FCMGT */
7369 845ea09a Peter Maydell
        handle_3same_float(s, size, elements, fpopcode, rd, rn, rm);
7370 845ea09a Peter Maydell
        return;
7371 845ea09a Peter Maydell
    default:
7372 845ea09a Peter Maydell
        unallocated_encoding(s);
7373 845ea09a Peter Maydell
        return;
7374 845ea09a Peter Maydell
    }
7375 e1cea114 Peter Maydell
}
7376 e1cea114 Peter Maydell
7377 e1cea114 Peter Maydell
/* Integer op subgroup of C3.6.16. */
7378 e1cea114 Peter Maydell
static void disas_simd_3same_int(DisasContext *s, uint32_t insn)
7379 e1cea114 Peter Maydell
{
7380 1f8a73af Peter Maydell
    int is_q = extract32(insn, 30, 1);
7381 1f8a73af Peter Maydell
    int u = extract32(insn, 29, 1);
7382 1f8a73af Peter Maydell
    int size = extract32(insn, 22, 2);
7383 1f8a73af Peter Maydell
    int opcode = extract32(insn, 11, 5);
7384 1f8a73af Peter Maydell
    int rm = extract32(insn, 16, 5);
7385 1f8a73af Peter Maydell
    int rn = extract32(insn, 5, 5);
7386 1f8a73af Peter Maydell
    int rd = extract32(insn, 0, 5);
7387 1f8a73af Peter Maydell
    int pass;
7388 1f8a73af Peter Maydell
7389 1f8a73af Peter Maydell
    switch (opcode) {
7390 1f8a73af Peter Maydell
    case 0x13: /* MUL, PMUL */
7391 1f8a73af Peter Maydell
        if (u && size != 0) {
7392 1f8a73af Peter Maydell
            unallocated_encoding(s);
7393 1f8a73af Peter Maydell
            return;
7394 1f8a73af Peter Maydell
        }
7395 1f8a73af Peter Maydell
        /* fall through */
7396 1f8a73af Peter Maydell
    case 0x0: /* SHADD, UHADD */
7397 1f8a73af Peter Maydell
    case 0x2: /* SRHADD, URHADD */
7398 1f8a73af Peter Maydell
    case 0x4: /* SHSUB, UHSUB */
7399 1f8a73af Peter Maydell
    case 0xc: /* SMAX, UMAX */
7400 1f8a73af Peter Maydell
    case 0xd: /* SMIN, UMIN */
7401 1f8a73af Peter Maydell
    case 0xe: /* SABD, UABD */
7402 1f8a73af Peter Maydell
    case 0xf: /* SABA, UABA */
7403 1f8a73af Peter Maydell
    case 0x12: /* MLA, MLS */
7404 1f8a73af Peter Maydell
        if (size == 3) {
7405 1f8a73af Peter Maydell
            unallocated_encoding(s);
7406 1f8a73af Peter Maydell
            return;
7407 1f8a73af Peter Maydell
        }
7408 8b12a0cf Peter Maydell
        break;
7409 1f8a73af Peter Maydell
    case 0x16: /* SQDMULH, SQRDMULH */
7410 1f8a73af Peter Maydell
        if (size == 0 || size == 3) {
7411 1f8a73af Peter Maydell
            unallocated_encoding(s);
7412 1f8a73af Peter Maydell
            return;
7413 1f8a73af Peter Maydell
        }
7414 8b12a0cf Peter Maydell
        break;
7415 1f8a73af Peter Maydell
    default:
7416 1f8a73af Peter Maydell
        if (size == 3 && !is_q) {
7417 1f8a73af Peter Maydell
            unallocated_encoding(s);
7418 1f8a73af Peter Maydell
            return;
7419 1f8a73af Peter Maydell
        }
7420 1f8a73af Peter Maydell
        break;
7421 1f8a73af Peter Maydell
    }
7422 1f8a73af Peter Maydell
7423 1f8a73af Peter Maydell
    if (size == 3) {
7424 1f8a73af Peter Maydell
        for (pass = 0; pass < (is_q ? 2 : 1); pass++) {
7425 1f8a73af Peter Maydell
            TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7426 1f8a73af Peter Maydell
            TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7427 1f8a73af Peter Maydell
            TCGv_i64 tcg_res = tcg_temp_new_i64();
7428 1f8a73af Peter Maydell
7429 1f8a73af Peter Maydell
            read_vec_element(s, tcg_op1, rn, pass, MO_64);
7430 1f8a73af Peter Maydell
            read_vec_element(s, tcg_op2, rm, pass, MO_64);
7431 1f8a73af Peter Maydell
7432 1f8a73af Peter Maydell
            handle_3same_64(s, opcode, u, tcg_res, tcg_op1, tcg_op2);
7433 1f8a73af Peter Maydell
7434 1f8a73af Peter Maydell
            write_vec_element(s, tcg_res, rd, pass, MO_64);
7435 1f8a73af Peter Maydell
7436 1f8a73af Peter Maydell
            tcg_temp_free_i64(tcg_res);
7437 1f8a73af Peter Maydell
            tcg_temp_free_i64(tcg_op1);
7438 1f8a73af Peter Maydell
            tcg_temp_free_i64(tcg_op2);
7439 1f8a73af Peter Maydell
        }
7440 1f8a73af Peter Maydell
    } else {
7441 1f8a73af Peter Maydell
        for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
7442 1f8a73af Peter Maydell
            TCGv_i32 tcg_op1 = tcg_temp_new_i32();
7443 1f8a73af Peter Maydell
            TCGv_i32 tcg_op2 = tcg_temp_new_i32();
7444 1f8a73af Peter Maydell
            TCGv_i32 tcg_res = tcg_temp_new_i32();
7445 6d9571f7 Peter Maydell
            NeonGenTwoOpFn *genfn = NULL;
7446 6d9571f7 Peter Maydell
            NeonGenTwoOpEnvFn *genenvfn = NULL;
7447 1f8a73af Peter Maydell
7448 1f8a73af Peter Maydell
            read_vec_element_i32(s, tcg_op1, rn, pass, MO_32);
7449 1f8a73af Peter Maydell
            read_vec_element_i32(s, tcg_op2, rm, pass, MO_32);
7450 1f8a73af Peter Maydell
7451 1f8a73af Peter Maydell
            switch (opcode) {
7452 8b12a0cf Peter Maydell
            case 0x0: /* SHADD, UHADD */
7453 8b12a0cf Peter Maydell
            {
7454 8b12a0cf Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7455 8b12a0cf Peter Maydell
                    { gen_helper_neon_hadd_s8, gen_helper_neon_hadd_u8 },
7456 8b12a0cf Peter Maydell
                    { gen_helper_neon_hadd_s16, gen_helper_neon_hadd_u16 },
7457 8b12a0cf Peter Maydell
                    { gen_helper_neon_hadd_s32, gen_helper_neon_hadd_u32 },
7458 8b12a0cf Peter Maydell
                };
7459 8b12a0cf Peter Maydell
                genfn = fns[size][u];
7460 8b12a0cf Peter Maydell
                break;
7461 8b12a0cf Peter Maydell
            }
7462 6d9571f7 Peter Maydell
            case 0x1: /* SQADD, UQADD */
7463 6d9571f7 Peter Maydell
            {
7464 6d9571f7 Peter Maydell
                static NeonGenTwoOpEnvFn * const fns[3][2] = {
7465 6d9571f7 Peter Maydell
                    { gen_helper_neon_qadd_s8, gen_helper_neon_qadd_u8 },
7466 6d9571f7 Peter Maydell
                    { gen_helper_neon_qadd_s16, gen_helper_neon_qadd_u16 },
7467 6d9571f7 Peter Maydell
                    { gen_helper_neon_qadd_s32, gen_helper_neon_qadd_u32 },
7468 6d9571f7 Peter Maydell
                };
7469 6d9571f7 Peter Maydell
                genenvfn = fns[size][u];
7470 6d9571f7 Peter Maydell
                break;
7471 6d9571f7 Peter Maydell
            }
7472 8b12a0cf Peter Maydell
            case 0x2: /* SRHADD, URHADD */
7473 8b12a0cf Peter Maydell
            {
7474 8b12a0cf Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7475 8b12a0cf Peter Maydell
                    { gen_helper_neon_rhadd_s8, gen_helper_neon_rhadd_u8 },
7476 8b12a0cf Peter Maydell
                    { gen_helper_neon_rhadd_s16, gen_helper_neon_rhadd_u16 },
7477 8b12a0cf Peter Maydell
                    { gen_helper_neon_rhadd_s32, gen_helper_neon_rhadd_u32 },
7478 8b12a0cf Peter Maydell
                };
7479 8b12a0cf Peter Maydell
                genfn = fns[size][u];
7480 8b12a0cf Peter Maydell
                break;
7481 8b12a0cf Peter Maydell
            }
7482 8b12a0cf Peter Maydell
            case 0x4: /* SHSUB, UHSUB */
7483 8b12a0cf Peter Maydell
            {
7484 8b12a0cf Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7485 8b12a0cf Peter Maydell
                    { gen_helper_neon_hsub_s8, gen_helper_neon_hsub_u8 },
7486 8b12a0cf Peter Maydell
                    { gen_helper_neon_hsub_s16, gen_helper_neon_hsub_u16 },
7487 8b12a0cf Peter Maydell
                    { gen_helper_neon_hsub_s32, gen_helper_neon_hsub_u32 },
7488 8b12a0cf Peter Maydell
                };
7489 8b12a0cf Peter Maydell
                genfn = fns[size][u];
7490 8b12a0cf Peter Maydell
                break;
7491 8b12a0cf Peter Maydell
            }
7492 6d9571f7 Peter Maydell
            case 0x5: /* SQSUB, UQSUB */
7493 6d9571f7 Peter Maydell
            {
7494 6d9571f7 Peter Maydell
                static NeonGenTwoOpEnvFn * const fns[3][2] = {
7495 6d9571f7 Peter Maydell
                    { gen_helper_neon_qsub_s8, gen_helper_neon_qsub_u8 },
7496 6d9571f7 Peter Maydell
                    { gen_helper_neon_qsub_s16, gen_helper_neon_qsub_u16 },
7497 6d9571f7 Peter Maydell
                    { gen_helper_neon_qsub_s32, gen_helper_neon_qsub_u32 },
7498 6d9571f7 Peter Maydell
                };
7499 6d9571f7 Peter Maydell
                genenvfn = fns[size][u];
7500 6d9571f7 Peter Maydell
                break;
7501 6d9571f7 Peter Maydell
            }
7502 1f8a73af Peter Maydell
            case 0x6: /* CMGT, CMHI */
7503 1f8a73af Peter Maydell
            {
7504 1f8a73af Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7505 1f8a73af Peter Maydell
                    { gen_helper_neon_cgt_s8, gen_helper_neon_cgt_u8 },
7506 1f8a73af Peter Maydell
                    { gen_helper_neon_cgt_s16, gen_helper_neon_cgt_u16 },
7507 1f8a73af Peter Maydell
                    { gen_helper_neon_cgt_s32, gen_helper_neon_cgt_u32 },
7508 1f8a73af Peter Maydell
                };
7509 1f8a73af Peter Maydell
                genfn = fns[size][u];
7510 1f8a73af Peter Maydell
                break;
7511 1f8a73af Peter Maydell
            }
7512 1f8a73af Peter Maydell
            case 0x7: /* CMGE, CMHS */
7513 1f8a73af Peter Maydell
            {
7514 1f8a73af Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7515 1f8a73af Peter Maydell
                    { gen_helper_neon_cge_s8, gen_helper_neon_cge_u8 },
7516 1f8a73af Peter Maydell
                    { gen_helper_neon_cge_s16, gen_helper_neon_cge_u16 },
7517 1f8a73af Peter Maydell
                    { gen_helper_neon_cge_s32, gen_helper_neon_cge_u32 },
7518 1f8a73af Peter Maydell
                };
7519 1f8a73af Peter Maydell
                genfn = fns[size][u];
7520 1f8a73af Peter Maydell
                break;
7521 1f8a73af Peter Maydell
            }
7522 6d9571f7 Peter Maydell
            case 0x8: /* SSHL, USHL */
7523 6d9571f7 Peter Maydell
            {
7524 6d9571f7 Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7525 6d9571f7 Peter Maydell
                    { gen_helper_neon_shl_s8, gen_helper_neon_shl_u8 },
7526 6d9571f7 Peter Maydell
                    { gen_helper_neon_shl_s16, gen_helper_neon_shl_u16 },
7527 6d9571f7 Peter Maydell
                    { gen_helper_neon_shl_s32, gen_helper_neon_shl_u32 },
7528 6d9571f7 Peter Maydell
                };
7529 6d9571f7 Peter Maydell
                genfn = fns[size][u];
7530 6d9571f7 Peter Maydell
                break;
7531 6d9571f7 Peter Maydell
            }
7532 6d9571f7 Peter Maydell
            case 0x9: /* SQSHL, UQSHL */
7533 6d9571f7 Peter Maydell
            {
7534 6d9571f7 Peter Maydell
                static NeonGenTwoOpEnvFn * const fns[3][2] = {
7535 6d9571f7 Peter Maydell
                    { gen_helper_neon_qshl_s8, gen_helper_neon_qshl_u8 },
7536 6d9571f7 Peter Maydell
                    { gen_helper_neon_qshl_s16, gen_helper_neon_qshl_u16 },
7537 6d9571f7 Peter Maydell
                    { gen_helper_neon_qshl_s32, gen_helper_neon_qshl_u32 },
7538 6d9571f7 Peter Maydell
                };
7539 6d9571f7 Peter Maydell
                genenvfn = fns[size][u];
7540 6d9571f7 Peter Maydell
                break;
7541 6d9571f7 Peter Maydell
            }
7542 6d9571f7 Peter Maydell
            case 0xa: /* SRSHL, URSHL */
7543 6d9571f7 Peter Maydell
            {
7544 6d9571f7 Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7545 6d9571f7 Peter Maydell
                    { gen_helper_neon_rshl_s8, gen_helper_neon_rshl_u8 },
7546 6d9571f7 Peter Maydell
                    { gen_helper_neon_rshl_s16, gen_helper_neon_rshl_u16 },
7547 6d9571f7 Peter Maydell
                    { gen_helper_neon_rshl_s32, gen_helper_neon_rshl_u32 },
7548 6d9571f7 Peter Maydell
                };
7549 6d9571f7 Peter Maydell
                genfn = fns[size][u];
7550 6d9571f7 Peter Maydell
                break;
7551 6d9571f7 Peter Maydell
            }
7552 6d9571f7 Peter Maydell
            case 0xb: /* SQRSHL, UQRSHL */
7553 6d9571f7 Peter Maydell
            {
7554 6d9571f7 Peter Maydell
                static NeonGenTwoOpEnvFn * const fns[3][2] = {
7555 6d9571f7 Peter Maydell
                    { gen_helper_neon_qrshl_s8, gen_helper_neon_qrshl_u8 },
7556 6d9571f7 Peter Maydell
                    { gen_helper_neon_qrshl_s16, gen_helper_neon_qrshl_u16 },
7557 6d9571f7 Peter Maydell
                    { gen_helper_neon_qrshl_s32, gen_helper_neon_qrshl_u32 },
7558 6d9571f7 Peter Maydell
                };
7559 6d9571f7 Peter Maydell
                genenvfn = fns[size][u];
7560 6d9571f7 Peter Maydell
                break;
7561 6d9571f7 Peter Maydell
            }
7562 8b12a0cf Peter Maydell
            case 0xc: /* SMAX, UMAX */
7563 8b12a0cf Peter Maydell
            {
7564 8b12a0cf Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7565 8b12a0cf Peter Maydell
                    { gen_helper_neon_max_s8, gen_helper_neon_max_u8 },
7566 8b12a0cf Peter Maydell
                    { gen_helper_neon_max_s16, gen_helper_neon_max_u16 },
7567 8b12a0cf Peter Maydell
                    { gen_max_s32, gen_max_u32 },
7568 8b12a0cf Peter Maydell
                };
7569 8b12a0cf Peter Maydell
                genfn = fns[size][u];
7570 8b12a0cf Peter Maydell
                break;
7571 8b12a0cf Peter Maydell
            }
7572 8b12a0cf Peter Maydell
7573 8b12a0cf Peter Maydell
            case 0xd: /* SMIN, UMIN */
7574 8b12a0cf Peter Maydell
            {
7575 8b12a0cf Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7576 8b12a0cf Peter Maydell
                    { gen_helper_neon_min_s8, gen_helper_neon_min_u8 },
7577 8b12a0cf Peter Maydell
                    { gen_helper_neon_min_s16, gen_helper_neon_min_u16 },
7578 8b12a0cf Peter Maydell
                    { gen_min_s32, gen_min_u32 },
7579 8b12a0cf Peter Maydell
                };
7580 8b12a0cf Peter Maydell
                genfn = fns[size][u];
7581 8b12a0cf Peter Maydell
                break;
7582 8b12a0cf Peter Maydell
            }
7583 8b12a0cf Peter Maydell
            case 0xe: /* SABD, UABD */
7584 8b12a0cf Peter Maydell
            case 0xf: /* SABA, UABA */
7585 8b12a0cf Peter Maydell
            {
7586 8b12a0cf Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7587 8b12a0cf Peter Maydell
                    { gen_helper_neon_abd_s8, gen_helper_neon_abd_u8 },
7588 8b12a0cf Peter Maydell
                    { gen_helper_neon_abd_s16, gen_helper_neon_abd_u16 },
7589 8b12a0cf Peter Maydell
                    { gen_helper_neon_abd_s32, gen_helper_neon_abd_u32 },
7590 8b12a0cf Peter Maydell
                };
7591 8b12a0cf Peter Maydell
                genfn = fns[size][u];
7592 8b12a0cf Peter Maydell
                break;
7593 8b12a0cf Peter Maydell
            }
7594 1f8a73af Peter Maydell
            case 0x10: /* ADD, SUB */
7595 1f8a73af Peter Maydell
            {
7596 1f8a73af Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7597 1f8a73af Peter Maydell
                    { gen_helper_neon_add_u8, gen_helper_neon_sub_u8 },
7598 1f8a73af Peter Maydell
                    { gen_helper_neon_add_u16, gen_helper_neon_sub_u16 },
7599 1f8a73af Peter Maydell
                    { tcg_gen_add_i32, tcg_gen_sub_i32 },
7600 1f8a73af Peter Maydell
                };
7601 1f8a73af Peter Maydell
                genfn = fns[size][u];
7602 1f8a73af Peter Maydell
                break;
7603 1f8a73af Peter Maydell
            }
7604 1f8a73af Peter Maydell
            case 0x11: /* CMTST, CMEQ */
7605 1f8a73af Peter Maydell
            {
7606 1f8a73af Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7607 1f8a73af Peter Maydell
                    { gen_helper_neon_tst_u8, gen_helper_neon_ceq_u8 },
7608 1f8a73af Peter Maydell
                    { gen_helper_neon_tst_u16, gen_helper_neon_ceq_u16 },
7609 1f8a73af Peter Maydell
                    { gen_helper_neon_tst_u32, gen_helper_neon_ceq_u32 },
7610 1f8a73af Peter Maydell
                };
7611 1f8a73af Peter Maydell
                genfn = fns[size][u];
7612 1f8a73af Peter Maydell
                break;
7613 1f8a73af Peter Maydell
            }
7614 8b12a0cf Peter Maydell
            case 0x13: /* MUL, PMUL */
7615 8b12a0cf Peter Maydell
                if (u) {
7616 8b12a0cf Peter Maydell
                    /* PMUL */
7617 8b12a0cf Peter Maydell
                    assert(size == 0);
7618 8b12a0cf Peter Maydell
                    genfn = gen_helper_neon_mul_p8;
7619 8b12a0cf Peter Maydell
                    break;
7620 8b12a0cf Peter Maydell
                }
7621 8b12a0cf Peter Maydell
                /* fall through : MUL */
7622 8b12a0cf Peter Maydell
            case 0x12: /* MLA, MLS */
7623 8b12a0cf Peter Maydell
            {
7624 8b12a0cf Peter Maydell
                static NeonGenTwoOpFn * const fns[3] = {
7625 8b12a0cf Peter Maydell
                    gen_helper_neon_mul_u8,
7626 8b12a0cf Peter Maydell
                    gen_helper_neon_mul_u16,
7627 8b12a0cf Peter Maydell
                    tcg_gen_mul_i32,
7628 8b12a0cf Peter Maydell
                };
7629 8b12a0cf Peter Maydell
                genfn = fns[size];
7630 8b12a0cf Peter Maydell
                break;
7631 8b12a0cf Peter Maydell
            }
7632 8b12a0cf Peter Maydell
            case 0x16: /* SQDMULH, SQRDMULH */
7633 8b12a0cf Peter Maydell
            {
7634 8b12a0cf Peter Maydell
                static NeonGenTwoOpEnvFn * const fns[2][2] = {
7635 8b12a0cf Peter Maydell
                    { gen_helper_neon_qdmulh_s16, gen_helper_neon_qrdmulh_s16 },
7636 8b12a0cf Peter Maydell
                    { gen_helper_neon_qdmulh_s32, gen_helper_neon_qrdmulh_s32 },
7637 8b12a0cf Peter Maydell
                };
7638 8b12a0cf Peter Maydell
                assert(size == 1 || size == 2);
7639 8b12a0cf Peter Maydell
                genenvfn = fns[size - 1][u];
7640 8b12a0cf Peter Maydell
                break;
7641 8b12a0cf Peter Maydell
            }
7642 1f8a73af Peter Maydell
            default:
7643 1f8a73af Peter Maydell
                g_assert_not_reached();
7644 1f8a73af Peter Maydell
            }
7645 1f8a73af Peter Maydell
7646 6d9571f7 Peter Maydell
            if (genenvfn) {
7647 6d9571f7 Peter Maydell
                genenvfn(tcg_res, cpu_env, tcg_op1, tcg_op2);
7648 6d9571f7 Peter Maydell
            } else {
7649 6d9571f7 Peter Maydell
                genfn(tcg_res, tcg_op1, tcg_op2);
7650 6d9571f7 Peter Maydell
            }
7651 1f8a73af Peter Maydell
7652 8b12a0cf Peter Maydell
            if (opcode == 0xf || opcode == 0x12) {
7653 8b12a0cf Peter Maydell
                /* SABA, UABA, MLA, MLS: accumulating ops */
7654 8b12a0cf Peter Maydell
                static NeonGenTwoOpFn * const fns[3][2] = {
7655 8b12a0cf Peter Maydell
                    { gen_helper_neon_add_u8, gen_helper_neon_sub_u8 },
7656 8b12a0cf Peter Maydell
                    { gen_helper_neon_add_u16, gen_helper_neon_sub_u16 },
7657 8b12a0cf Peter Maydell
                    { tcg_gen_add_i32, tcg_gen_sub_i32 },
7658 8b12a0cf Peter Maydell
                };
7659 8b12a0cf Peter Maydell
                bool is_sub = (opcode == 0x12 && u); /* MLS */
7660 8b12a0cf Peter Maydell
7661 8b12a0cf Peter Maydell
                genfn = fns[size][is_sub];
7662 8b12a0cf Peter Maydell
                read_vec_element_i32(s, tcg_op1, rd, pass, MO_32);
7663 8b12a0cf Peter Maydell
                genfn(tcg_res, tcg_res, tcg_op1);
7664 8b12a0cf Peter Maydell
            }
7665 8b12a0cf Peter Maydell
7666 1f8a73af Peter Maydell
            write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
7667 1f8a73af Peter Maydell
7668 1f8a73af Peter Maydell
            tcg_temp_free_i32(tcg_res);
7669 1f8a73af Peter Maydell
            tcg_temp_free_i32(tcg_op1);
7670 1f8a73af Peter Maydell
            tcg_temp_free_i32(tcg_op2);
7671 1f8a73af Peter Maydell
        }
7672 1f8a73af Peter Maydell
    }
7673 1f8a73af Peter Maydell
7674 1f8a73af Peter Maydell
    if (!is_q) {
7675 1f8a73af Peter Maydell
        clear_vec_high(s, rd);
7676 1f8a73af Peter Maydell
    }
7677 e1cea114 Peter Maydell
}
7678 e1cea114 Peter Maydell
7679 384b26fb Alex Bennée
/* C3.6.16 AdvSIMD three same
7680 384b26fb Alex Bennée
 *  31  30  29  28       24 23  22  21 20  16 15    11  10 9    5 4    0
7681 384b26fb Alex Bennée
 * +---+---+---+-----------+------+---+------+--------+---+------+------+
7682 384b26fb Alex Bennée
 * | 0 | Q | U | 0 1 1 1 0 | size | 1 |  Rm  | opcode | 1 |  Rn  |  Rd  |
7683 384b26fb Alex Bennée
 * +---+---+---+-----------+------+---+------+--------+---+------+------+
7684 384b26fb Alex Bennée
 */
7685 384b26fb Alex Bennée
static void disas_simd_three_reg_same(DisasContext *s, uint32_t insn)
7686 384b26fb Alex Bennée
{
7687 e1cea114 Peter Maydell
    int opcode = extract32(insn, 11, 5);
7688 e1cea114 Peter Maydell
7689 e1cea114 Peter Maydell
    switch (opcode) {
7690 e1cea114 Peter Maydell
    case 0x3: /* logic ops */
7691 e1cea114 Peter Maydell
        disas_simd_3same_logic(s, insn);
7692 e1cea114 Peter Maydell
        break;
7693 e1cea114 Peter Maydell
    case 0x17: /* ADDP */
7694 e1cea114 Peter Maydell
    case 0x14: /* SMAXP, UMAXP */
7695 e1cea114 Peter Maydell
    case 0x15: /* SMINP, UMINP */
7696 bc242f9b Alex Bennée
    {
7697 e1cea114 Peter Maydell
        /* Pairwise operations */
7698 bc242f9b Alex Bennée
        int is_q = extract32(insn, 30, 1);
7699 bc242f9b Alex Bennée
        int u = extract32(insn, 29, 1);
7700 bc242f9b Alex Bennée
        int size = extract32(insn, 22, 2);
7701 bc242f9b Alex Bennée
        int rm = extract32(insn, 16, 5);
7702 bc242f9b Alex Bennée
        int rn = extract32(insn, 5, 5);
7703 bc242f9b Alex Bennée
        int rd = extract32(insn, 0, 5);
7704 bc242f9b Alex Bennée
        if (opcode == 0x17) {
7705 bc242f9b Alex Bennée
            if (u || (size == 3 && !is_q)) {
7706 bc242f9b Alex Bennée
                unallocated_encoding(s);
7707 bc242f9b Alex Bennée
                return;
7708 bc242f9b Alex Bennée
            }
7709 bc242f9b Alex Bennée
        } else {
7710 bc242f9b Alex Bennée
            if (size == 3) {
7711 bc242f9b Alex Bennée
                unallocated_encoding(s);
7712 bc242f9b Alex Bennée
                return;
7713 bc242f9b Alex Bennée
            }
7714 bc242f9b Alex Bennée
        }
7715 bc242f9b Alex Bennée
        handle_simd_3same_pair(s, is_q, u, opcode, size, rn, rm, rd);
7716 e1cea114 Peter Maydell
        break;
7717 bc242f9b Alex Bennée
    }
7718 e1cea114 Peter Maydell
    case 0x18 ... 0x31:
7719 e1cea114 Peter Maydell
        /* floating point ops, sz[1] and U are part of opcode */
7720 e1cea114 Peter Maydell
        disas_simd_3same_float(s, insn);
7721 e1cea114 Peter Maydell
        break;
7722 e1cea114 Peter Maydell
    default:
7723 e1cea114 Peter Maydell
        disas_simd_3same_int(s, insn);
7724 e1cea114 Peter Maydell
        break;
7725 e1cea114 Peter Maydell
    }
7726 384b26fb Alex Bennée
}
7727 384b26fb Alex Bennée
7728 d980fd59 Peter Maydell
static void handle_2misc_narrow(DisasContext *s, int opcode, bool u, bool is_q,
7729 d980fd59 Peter Maydell
                                int size, int rn, int rd)
7730 d980fd59 Peter Maydell
{
7731 d980fd59 Peter Maydell
    /* Handle 2-reg-misc ops which are narrowing (so each 2*size element
7732 d980fd59 Peter Maydell
     * in the source becomes a size element in the destination).
7733 d980fd59 Peter Maydell
     */
7734 d980fd59 Peter Maydell
    int pass;
7735 d980fd59 Peter Maydell
    TCGv_i32 tcg_res[2];
7736 d980fd59 Peter Maydell
    int destelt = is_q ? 2 : 0;
7737 d980fd59 Peter Maydell
7738 d980fd59 Peter Maydell
    for (pass = 0; pass < 2; pass++) {
7739 d980fd59 Peter Maydell
        TCGv_i64 tcg_op = tcg_temp_new_i64();
7740 d980fd59 Peter Maydell
        NeonGenNarrowFn *genfn = NULL;
7741 d980fd59 Peter Maydell
        NeonGenNarrowEnvFn *genenvfn = NULL;
7742 d980fd59 Peter Maydell
7743 d980fd59 Peter Maydell
        read_vec_element(s, tcg_op, rn, pass, MO_64);
7744 d980fd59 Peter Maydell
        tcg_res[pass] = tcg_temp_new_i32();
7745 d980fd59 Peter Maydell
7746 d980fd59 Peter Maydell
        switch (opcode) {
7747 d980fd59 Peter Maydell
        case 0x12: /* XTN, SQXTUN */
7748 d980fd59 Peter Maydell
        {
7749 d980fd59 Peter Maydell
            static NeonGenNarrowFn * const xtnfns[3] = {
7750 d980fd59 Peter Maydell
                gen_helper_neon_narrow_u8,
7751 d980fd59 Peter Maydell
                gen_helper_neon_narrow_u16,
7752 d980fd59 Peter Maydell
                tcg_gen_trunc_i64_i32,
7753 d980fd59 Peter Maydell
            };
7754 d980fd59 Peter Maydell
            static NeonGenNarrowEnvFn * const sqxtunfns[3] = {
7755 d980fd59 Peter Maydell
                gen_helper_neon_unarrow_sat8,
7756 d980fd59 Peter Maydell
                gen_helper_neon_unarrow_sat16,
7757 d980fd59 Peter Maydell
                gen_helper_neon_unarrow_sat32,
7758 d980fd59 Peter Maydell
            };
7759 d980fd59 Peter Maydell
            if (u) {
7760 d980fd59 Peter Maydell
                genenvfn = sqxtunfns[size];
7761 d980fd59 Peter Maydell
            } else {
7762 d980fd59 Peter Maydell
                genfn = xtnfns[size];
7763 d980fd59 Peter Maydell
            }
7764 d980fd59 Peter Maydell
            break;
7765 d980fd59 Peter Maydell
        }
7766 d980fd59 Peter Maydell
        case 0x14: /* SQXTN, UQXTN */
7767 d980fd59 Peter Maydell
        {
7768 d980fd59 Peter Maydell
            static NeonGenNarrowEnvFn * const fns[3][2] = {
7769 d980fd59 Peter Maydell
                { gen_helper_neon_narrow_sat_s8,
7770 d980fd59 Peter Maydell
                  gen_helper_neon_narrow_sat_u8 },
7771 d980fd59 Peter Maydell
                { gen_helper_neon_narrow_sat_s16,
7772 d980fd59 Peter Maydell
                  gen_helper_neon_narrow_sat_u16 },
7773 d980fd59 Peter Maydell
                { gen_helper_neon_narrow_sat_s32,
7774 d980fd59 Peter Maydell
                  gen_helper_neon_narrow_sat_u32 },
7775 d980fd59 Peter Maydell
            };
7776 d980fd59 Peter Maydell
            genenvfn = fns[size][u];
7777 d980fd59 Peter Maydell
            break;
7778 d980fd59 Peter Maydell
        }
7779 d980fd59 Peter Maydell
        default:
7780 d980fd59 Peter Maydell
            g_assert_not_reached();
7781 d980fd59 Peter Maydell
        }
7782 d980fd59 Peter Maydell
7783 d980fd59 Peter Maydell
        if (genfn) {
7784 d980fd59 Peter Maydell
            genfn(tcg_res[pass], tcg_op);
7785 d980fd59 Peter Maydell
        } else {
7786 d980fd59 Peter Maydell
            genenvfn(tcg_res[pass], cpu_env, tcg_op);
7787 d980fd59 Peter Maydell
        }
7788 d980fd59 Peter Maydell
7789 d980fd59 Peter Maydell
        tcg_temp_free_i64(tcg_op);
7790 d980fd59 Peter Maydell
    }
7791 d980fd59 Peter Maydell
7792 d980fd59 Peter Maydell
    for (pass = 0; pass < 2; pass++) {
7793 d980fd59 Peter Maydell
        write_vec_element_i32(s, tcg_res[pass], rd, destelt + pass, MO_32);
7794 d980fd59 Peter Maydell
        tcg_temp_free_i32(tcg_res[pass]);
7795 d980fd59 Peter Maydell
    }
7796 d980fd59 Peter Maydell
    if (!is_q) {
7797 d980fd59 Peter Maydell
        clear_vec_high(s, rd);
7798 d980fd59 Peter Maydell
    }
7799 d980fd59 Peter Maydell
}
7800 d980fd59 Peter Maydell
7801 39d82118 Alex Bennée
static void handle_rev(DisasContext *s, int opcode, bool u,
7802 39d82118 Alex Bennée
                       bool is_q, int size, int rn, int rd)
7803 39d82118 Alex Bennée
{
7804 39d82118 Alex Bennée
    int op = (opcode << 1) | u;
7805 39d82118 Alex Bennée
    int opsz = op + size;
7806 39d82118 Alex Bennée
    int grp_size = 3 - opsz;
7807 39d82118 Alex Bennée
    int dsize = is_q ? 128 : 64;
7808 39d82118 Alex Bennée
    int i;
7809 39d82118 Alex Bennée
7810 39d82118 Alex Bennée
    if (opsz >= 3) {
7811 39d82118 Alex Bennée
        unallocated_encoding(s);
7812 39d82118 Alex Bennée
        return;
7813 39d82118 Alex Bennée
    }
7814 39d82118 Alex Bennée
7815 39d82118 Alex Bennée
    if (size == 0) {
7816 39d82118 Alex Bennée
        /* Special case bytes, use bswap op on each group of elements */
7817 39d82118 Alex Bennée
        int groups = dsize / (8 << grp_size);
7818 39d82118 Alex Bennée
7819 39d82118 Alex Bennée
        for (i = 0; i < groups; i++) {
7820 39d82118 Alex Bennée
            TCGv_i64 tcg_tmp = tcg_temp_new_i64();
7821 39d82118 Alex Bennée
7822 39d82118 Alex Bennée
            read_vec_element(s, tcg_tmp, rn, i, grp_size);
7823 39d82118 Alex Bennée
            switch (grp_size) {
7824 39d82118 Alex Bennée
            case MO_16:
7825 39d82118 Alex Bennée
                tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp);
7826 39d82118 Alex Bennée
                break;
7827 39d82118 Alex Bennée
            case MO_32:
7828 39d82118 Alex Bennée
                tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp);
7829 39d82118 Alex Bennée
                break;
7830 39d82118 Alex Bennée
            case MO_64:
7831 39d82118 Alex Bennée
                tcg_gen_bswap64_i64(tcg_tmp, tcg_tmp);
7832 39d82118 Alex Bennée
                break;
7833 39d82118 Alex Bennée
            default:
7834 39d82118 Alex Bennée
                g_assert_not_reached();
7835 39d82118 Alex Bennée
            }
7836 39d82118 Alex Bennée
            write_vec_element(s, tcg_tmp, rd, i, grp_size);
7837 39d82118 Alex Bennée
            tcg_temp_free_i64(tcg_tmp);
7838 39d82118 Alex Bennée
        }
7839 39d82118 Alex Bennée
        if (!is_q) {
7840 39d82118 Alex Bennée
            clear_vec_high(s, rd);
7841 39d82118 Alex Bennée
        }
7842 39d82118 Alex Bennée
    } else {
7843 39d82118 Alex Bennée
        int revmask = (1 << grp_size) - 1;
7844 39d82118 Alex Bennée
        int esize = 8 << size;
7845 39d82118 Alex Bennée
        int elements = dsize / esize;
7846 39d82118 Alex Bennée
        TCGv_i64 tcg_rn = tcg_temp_new_i64();
7847 39d82118 Alex Bennée
        TCGv_i64 tcg_rd = tcg_const_i64(0);
7848 39d82118 Alex Bennée
        TCGv_i64 tcg_rd_hi = tcg_const_i64(0);
7849 39d82118 Alex Bennée
7850 39d82118 Alex Bennée
        for (i = 0; i < elements; i++) {
7851 39d82118 Alex Bennée
            int e_rev = (i & 0xf) ^ revmask;
7852 39d82118 Alex Bennée
            int off = e_rev * esize;
7853 39d82118 Alex Bennée
            read_vec_element(s, tcg_rn, rn, i, size);
7854 39d82118 Alex Bennée
            if (off >= 64) {
7855 39d82118 Alex Bennée
                tcg_gen_deposit_i64(tcg_rd_hi, tcg_rd_hi,
7856 39d82118 Alex Bennée
                                    tcg_rn, off - 64, esize);
7857 39d82118 Alex Bennée
            } else {
7858 39d82118 Alex Bennée
                tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, off, esize);
7859 39d82118 Alex Bennée
            }
7860 39d82118 Alex Bennée
        }
7861 39d82118 Alex Bennée
        write_vec_element(s, tcg_rd, rd, 0, MO_64);
7862 39d82118 Alex Bennée
        write_vec_element(s, tcg_rd_hi, rd, 1, MO_64);
7863 39d82118 Alex Bennée
7864 39d82118 Alex Bennée
        tcg_temp_free_i64(tcg_rd_hi);
7865 39d82118 Alex Bennée
        tcg_temp_free_i64(tcg_rd);
7866 39d82118 Alex Bennée
        tcg_temp_free_i64(tcg_rn);
7867 39d82118 Alex Bennée
    }
7868 39d82118 Alex Bennée
}
7869 39d82118 Alex Bennée
7870 384b26fb Alex Bennée
/* C3.6.17 AdvSIMD two reg misc
7871 384b26fb Alex Bennée
 *   31  30  29 28       24 23  22 21       17 16    12 11 10 9    5 4    0
7872 384b26fb Alex Bennée
 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
7873 384b26fb Alex Bennée
 * | 0 | Q | U | 0 1 1 1 0 | size | 1 0 0 0 0 | opcode | 1 0 |  Rn  |  Rd  |
7874 384b26fb Alex Bennée
 * +---+---+---+-----------+------+-----------+--------+-----+------+------+
7875 384b26fb Alex Bennée
 */
7876 384b26fb Alex Bennée
static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
7877 384b26fb Alex Bennée
{
7878 45aecc6d Peter Maydell
    int size = extract32(insn, 22, 2);
7879 45aecc6d Peter Maydell
    int opcode = extract32(insn, 12, 5);
7880 45aecc6d Peter Maydell
    bool u = extract32(insn, 29, 1);
7881 45aecc6d Peter Maydell
    bool is_q = extract32(insn, 30, 1);
7882 94b6c911 Peter Maydell
    int rn = extract32(insn, 5, 5);
7883 94b6c911 Peter Maydell
    int rd = extract32(insn, 0, 5);
7884 45aecc6d Peter Maydell
7885 45aecc6d Peter Maydell
    switch (opcode) {
7886 45aecc6d Peter Maydell
    case 0x0: /* REV64, REV32 */
7887 45aecc6d Peter Maydell
    case 0x1: /* REV16 */
7888 39d82118 Alex Bennée
        handle_rev(s, opcode, u, is_q, size, rn, rd);
7889 45aecc6d Peter Maydell
        return;
7890 86cbc418 Peter Maydell
    case 0x5: /* CNT, NOT, RBIT */
7891 86cbc418 Peter Maydell
        if (u && size == 0) {
7892 86cbc418 Peter Maydell
            /* NOT: adjust size so we can use the 64-bits-at-a-time loop. */
7893 86cbc418 Peter Maydell
            size = 3;
7894 86cbc418 Peter Maydell
            break;
7895 86cbc418 Peter Maydell
        } else if (u && size == 1) {
7896 86cbc418 Peter Maydell
            /* RBIT */
7897 86cbc418 Peter Maydell
            break;
7898 86cbc418 Peter Maydell
        } else if (!u && size == 0) {
7899 86cbc418 Peter Maydell
            /* CNT */
7900 86cbc418 Peter Maydell
            break;
7901 45aecc6d Peter Maydell
        }
7902 86cbc418 Peter Maydell
        unallocated_encoding(s);
7903 45aecc6d Peter Maydell
        return;
7904 d980fd59 Peter Maydell
    case 0x12: /* XTN, XTN2, SQXTUN, SQXTUN2 */
7905 d980fd59 Peter Maydell
    case 0x14: /* SQXTN, SQXTN2, UQXTN, UQXTN2 */
7906 d980fd59 Peter Maydell
        if (size == 3) {
7907 d980fd59 Peter Maydell
            unallocated_encoding(s);
7908 d980fd59 Peter Maydell
            return;
7909 d980fd59 Peter Maydell
        }
7910 d980fd59 Peter Maydell
        handle_2misc_narrow(s, opcode, u, is_q, size, rn, rd);
7911 d980fd59 Peter Maydell
        return;
7912 45aecc6d Peter Maydell
    case 0x2: /* SADDLP, UADDLP */
7913 45aecc6d Peter Maydell
    case 0x4: /* CLS, CLZ */
7914 45aecc6d Peter Maydell
    case 0x6: /* SADALP, UADALP */
7915 45aecc6d Peter Maydell
        if (size == 3) {
7916 45aecc6d Peter Maydell
            unallocated_encoding(s);
7917 45aecc6d Peter Maydell
            return;
7918 45aecc6d Peter Maydell
        }
7919 45aecc6d Peter Maydell
        unsupported_encoding(s, insn);
7920 45aecc6d Peter Maydell
        return;
7921 45aecc6d Peter Maydell
    case 0x13: /* SHLL, SHLL2 */
7922 45aecc6d Peter Maydell
        if (u == 0 || size == 3) {
7923 45aecc6d Peter Maydell
            unallocated_encoding(s);
7924 45aecc6d Peter Maydell
            return;
7925 45aecc6d Peter Maydell
        }
7926 45aecc6d Peter Maydell
        unsupported_encoding(s, insn);
7927 45aecc6d Peter Maydell
        return;
7928 45aecc6d Peter Maydell
    case 0xa: /* CMLT */
7929 45aecc6d Peter Maydell
        if (u == 1) {
7930 45aecc6d Peter Maydell
            unallocated_encoding(s);
7931 45aecc6d Peter Maydell
            return;
7932 45aecc6d Peter Maydell
        }
7933 45aecc6d Peter Maydell
        /* fall through */
7934 45aecc6d Peter Maydell
    case 0x8: /* CMGT, CMGE */
7935 45aecc6d Peter Maydell
    case 0x9: /* CMEQ, CMLE */
7936 45aecc6d Peter Maydell
    case 0xb: /* ABS, NEG */
7937 45aecc6d Peter Maydell
        if (size == 3 && !is_q) {
7938 45aecc6d Peter Maydell
            unallocated_encoding(s);
7939 45aecc6d Peter Maydell
            return;
7940 45aecc6d Peter Maydell
        }
7941 94b6c911 Peter Maydell
        break;
7942 94b6c911 Peter Maydell
    case 0x3: /* SUQADD, USQADD */
7943 94b6c911 Peter Maydell
    case 0x7: /* SQABS, SQNEG */
7944 94b6c911 Peter Maydell
        if (size == 3 && !is_q) {
7945 94b6c911 Peter Maydell
            unallocated_encoding(s);
7946 94b6c911 Peter Maydell
            return;
7947 94b6c911 Peter Maydell
        }
7948 45aecc6d Peter Maydell
        unsupported_encoding(s, insn);
7949 45aecc6d Peter Maydell
        return;
7950 45aecc6d Peter Maydell
    case 0xc ... 0xf:
7951 45aecc6d Peter Maydell
    case 0x16 ... 0x1d:
7952 45aecc6d Peter Maydell
    case 0x1f:
7953 45aecc6d Peter Maydell
    {
7954 45aecc6d Peter Maydell
        /* Floating point: U, size[1] and opcode indicate operation;
7955 45aecc6d Peter Maydell
         * size[0] indicates single or double precision.
7956 45aecc6d Peter Maydell
         */
7957 45aecc6d Peter Maydell
        opcode |= (extract32(size, 1, 1) << 5) | (u << 6);
7958 45aecc6d Peter Maydell
        size = extract32(size, 0, 1) ? 3 : 2;
7959 45aecc6d Peter Maydell
        switch (opcode) {
7960 f93d0138 Peter Maydell
        case 0x2f: /* FABS */
7961 f93d0138 Peter Maydell
        case 0x6f: /* FNEG */
7962 f93d0138 Peter Maydell
            if (size == 3 && !is_q) {
7963 f93d0138 Peter Maydell
                unallocated_encoding(s);
7964 f93d0138 Peter Maydell
                return;
7965 f93d0138 Peter Maydell
            }
7966 f93d0138 Peter Maydell
            break;
7967 8908f4d1 Alex Bennée
        case 0x2c: /* FCMGT (zero) */
7968 8908f4d1 Alex Bennée
        case 0x2d: /* FCMEQ (zero) */
7969 8908f4d1 Alex Bennée
        case 0x2e: /* FCMLT (zero) */
7970 8908f4d1 Alex Bennée
        case 0x6c: /* FCMGE (zero) */
7971 8908f4d1 Alex Bennée
        case 0x6d: /* FCMLE (zero) */
7972 8908f4d1 Alex Bennée
            if (size == 3 && !is_q) {
7973 8908f4d1 Alex Bennée
                unallocated_encoding(s);
7974 8908f4d1 Alex Bennée
                return;
7975 8908f4d1 Alex Bennée
            }
7976 8908f4d1 Alex Bennée
            handle_2misc_fcmp_zero(s, opcode, false, u, is_q, size, rn, rd);
7977 8908f4d1 Alex Bennée
            return;
7978 45aecc6d Peter Maydell
        case 0x16: /* FCVTN, FCVTN2 */
7979 45aecc6d Peter Maydell
        case 0x17: /* FCVTL, FCVTL2 */
7980 45aecc6d Peter Maydell
        case 0x18: /* FRINTN */
7981 45aecc6d Peter Maydell
        case 0x19: /* FRINTM */
7982 45aecc6d Peter Maydell
        case 0x1a: /* FCVTNS */
7983 45aecc6d Peter Maydell
        case 0x1b: /* FCVTMS */
7984 45aecc6d Peter Maydell
        case 0x1c: /* FCVTAS */
7985 45aecc6d Peter Maydell
        case 0x1d: /* SCVTF */
7986 45aecc6d Peter Maydell
        case 0x38: /* FRINTP */
7987 45aecc6d Peter Maydell
        case 0x39: /* FRINTZ */
7988 45aecc6d Peter Maydell
        case 0x3a: /* FCVTPS */
7989 45aecc6d Peter Maydell
        case 0x3b: /* FCVTZS */
7990 45aecc6d Peter Maydell
        case 0x3c: /* URECPE */
7991 45aecc6d Peter Maydell
        case 0x3d: /* FRECPE */
7992 45aecc6d Peter Maydell
        case 0x56: /* FCVTXN, FCVTXN2 */
7993 45aecc6d Peter Maydell
        case 0x58: /* FRINTA */
7994 45aecc6d Peter Maydell
        case 0x59: /* FRINTX */
7995 45aecc6d Peter Maydell
        case 0x5a: /* FCVTNU */
7996 45aecc6d Peter Maydell
        case 0x5b: /* FCVTMU */
7997 45aecc6d Peter Maydell
        case 0x5c: /* FCVTAU */
7998 45aecc6d Peter Maydell
        case 0x5d: /* UCVTF */
7999 45aecc6d Peter Maydell
        case 0x79: /* FRINTI */
8000 45aecc6d Peter Maydell
        case 0x7a: /* FCVTPU */
8001 45aecc6d Peter Maydell
        case 0x7b: /* FCVTZU */
8002 45aecc6d Peter Maydell
        case 0x7c: /* URSQRTE */
8003 45aecc6d Peter Maydell
        case 0x7d: /* FRSQRTE */
8004 45aecc6d Peter Maydell
        case 0x7f: /* FSQRT */
8005 45aecc6d Peter Maydell
            unsupported_encoding(s, insn);
8006 45aecc6d Peter Maydell
            return;
8007 45aecc6d Peter Maydell
        default:
8008 45aecc6d Peter Maydell
            unallocated_encoding(s);
8009 45aecc6d Peter Maydell
            return;
8010 45aecc6d Peter Maydell
        }
8011 45aecc6d Peter Maydell
        break;
8012 45aecc6d Peter Maydell
    }
8013 45aecc6d Peter Maydell
    default:
8014 45aecc6d Peter Maydell
        unallocated_encoding(s);
8015 45aecc6d Peter Maydell
        return;
8016 45aecc6d Peter Maydell
    }
8017 94b6c911 Peter Maydell
8018 94b6c911 Peter Maydell
    if (size == 3) {
8019 94b6c911 Peter Maydell
        /* All 64-bit element operations can be shared with scalar 2misc */
8020 94b6c911 Peter Maydell
        int pass;
8021 94b6c911 Peter Maydell
8022 94b6c911 Peter Maydell
        for (pass = 0; pass < (is_q ? 2 : 1); pass++) {
8023 94b6c911 Peter Maydell
            TCGv_i64 tcg_op = tcg_temp_new_i64();
8024 94b6c911 Peter Maydell
            TCGv_i64 tcg_res = tcg_temp_new_i64();
8025 94b6c911 Peter Maydell
8026 94b6c911 Peter Maydell
            read_vec_element(s, tcg_op, rn, pass, MO_64);
8027 94b6c911 Peter Maydell
8028 94b6c911 Peter Maydell
            handle_2misc_64(s, opcode, u, tcg_res, tcg_op);
8029 94b6c911 Peter Maydell
8030 94b6c911 Peter Maydell
            write_vec_element(s, tcg_res, rd, pass, MO_64);
8031 94b6c911 Peter Maydell
8032 94b6c911 Peter Maydell
            tcg_temp_free_i64(tcg_res);
8033 94b6c911 Peter Maydell
            tcg_temp_free_i64(tcg_op);
8034 94b6c911 Peter Maydell
        }
8035 94b6c911 Peter Maydell
    } else {
8036 94b6c911 Peter Maydell
        int pass;
8037 94b6c911 Peter Maydell
8038 94b6c911 Peter Maydell
        for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
8039 94b6c911 Peter Maydell
            TCGv_i32 tcg_op = tcg_temp_new_i32();
8040 94b6c911 Peter Maydell
            TCGv_i32 tcg_res = tcg_temp_new_i32();
8041 94b6c911 Peter Maydell
            TCGCond cond;
8042 94b6c911 Peter Maydell
8043 94b6c911 Peter Maydell
            read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
8044 94b6c911 Peter Maydell
8045 94b6c911 Peter Maydell
            if (size == 2) {
8046 94b6c911 Peter Maydell
                /* Special cases for 32 bit elements */
8047 94b6c911 Peter Maydell
                switch (opcode) {
8048 94b6c911 Peter Maydell
                case 0xa: /* CMLT */
8049 94b6c911 Peter Maydell
                    /* 32 bit integer comparison against zero, result is
8050 94b6c911 Peter Maydell
                     * test ? (2^32 - 1) : 0. We implement via setcond(test)
8051 94b6c911 Peter Maydell
                     * and inverting.
8052 94b6c911 Peter Maydell
                     */
8053 94b6c911 Peter Maydell
                    cond = TCG_COND_LT;
8054 94b6c911 Peter Maydell
                do_cmop:
8055 94b6c911 Peter Maydell
                    tcg_gen_setcondi_i32(cond, tcg_res, tcg_op, 0);
8056 94b6c911 Peter Maydell
                    tcg_gen_neg_i32(tcg_res, tcg_res);
8057 94b6c911 Peter Maydell
                    break;
8058 94b6c911 Peter Maydell
                case 0x8: /* CMGT, CMGE */
8059 94b6c911 Peter Maydell
                    cond = u ? TCG_COND_GE : TCG_COND_GT;
8060 94b6c911 Peter Maydell
                    goto do_cmop;
8061 94b6c911 Peter Maydell
                case 0x9: /* CMEQ, CMLE */
8062 94b6c911 Peter Maydell
                    cond = u ? TCG_COND_LE : TCG_COND_EQ;
8063 94b6c911 Peter Maydell
                    goto do_cmop;
8064 94b6c911 Peter Maydell
                case 0xb: /* ABS, NEG */
8065 94b6c911 Peter Maydell
                    if (u) {
8066 94b6c911 Peter Maydell
                        tcg_gen_neg_i32(tcg_res, tcg_op);
8067 94b6c911 Peter Maydell
                    } else {
8068 94b6c911 Peter Maydell
                        TCGv_i32 tcg_zero = tcg_const_i32(0);
8069 94b6c911 Peter Maydell
                        tcg_gen_neg_i32(tcg_res, tcg_op);
8070 94b6c911 Peter Maydell
                        tcg_gen_movcond_i32(TCG_COND_GT, tcg_res, tcg_op,
8071 94b6c911 Peter Maydell
                                            tcg_zero, tcg_op, tcg_res);
8072 94b6c911 Peter Maydell
                        tcg_temp_free_i32(tcg_zero);
8073 94b6c911 Peter Maydell
                    }
8074 94b6c911 Peter Maydell
                    break;
8075 f93d0138 Peter Maydell
                case 0x2f: /* FABS */
8076 f93d0138 Peter Maydell
                    gen_helper_vfp_abss(tcg_res, tcg_op);
8077 f93d0138 Peter Maydell
                    break;
8078 f93d0138 Peter Maydell
                case 0x6f: /* FNEG */
8079 f93d0138 Peter Maydell
                    gen_helper_vfp_negs(tcg_res, tcg_op);
8080 f93d0138 Peter Maydell
                    break;
8081 94b6c911 Peter Maydell
                default:
8082 94b6c911 Peter Maydell
                    g_assert_not_reached();
8083 94b6c911 Peter Maydell
                }
8084 94b6c911 Peter Maydell
            } else {
8085 94b6c911 Peter Maydell
                /* Use helpers for 8 and 16 bit elements */
8086 94b6c911 Peter Maydell
                switch (opcode) {
8087 86cbc418 Peter Maydell
                case 0x5: /* CNT, RBIT */
8088 86cbc418 Peter Maydell
                    /* For these two insns size is part of the opcode specifier
8089 86cbc418 Peter Maydell
                     * (handled earlier); they always operate on byte elements.
8090 86cbc418 Peter Maydell
                     */
8091 86cbc418 Peter Maydell
                    if (u) {
8092 86cbc418 Peter Maydell
                        gen_helper_neon_rbit_u8(tcg_res, tcg_op);
8093 86cbc418 Peter Maydell
                    } else {
8094 86cbc418 Peter Maydell
                        gen_helper_neon_cnt_u8(tcg_res, tcg_op);
8095 86cbc418 Peter Maydell
                    }
8096 86cbc418 Peter Maydell
                    break;
8097 94b6c911 Peter Maydell
                case 0x8: /* CMGT, CMGE */
8098 94b6c911 Peter Maydell
                case 0x9: /* CMEQ, CMLE */
8099 94b6c911 Peter Maydell
                case 0xa: /* CMLT */
8100 94b6c911 Peter Maydell
                {
8101 94b6c911 Peter Maydell
                    static NeonGenTwoOpFn * const fns[3][2] = {
8102 94b6c911 Peter Maydell
                        { gen_helper_neon_cgt_s8, gen_helper_neon_cgt_s16 },
8103 94b6c911 Peter Maydell
                        { gen_helper_neon_cge_s8, gen_helper_neon_cge_s16 },
8104 94b6c911 Peter Maydell
                        { gen_helper_neon_ceq_u8, gen_helper_neon_ceq_u16 },
8105 94b6c911 Peter Maydell
                    };
8106 94b6c911 Peter Maydell
                    NeonGenTwoOpFn *genfn;
8107 94b6c911 Peter Maydell
                    int comp;
8108 94b6c911 Peter Maydell
                    bool reverse;
8109 94b6c911 Peter Maydell
                    TCGv_i32 tcg_zero = tcg_const_i32(0);
8110 94b6c911 Peter Maydell
8111 94b6c911 Peter Maydell
                    /* comp = index into [CMGT, CMGE, CMEQ, CMLE, CMLT] */
8112 94b6c911 Peter Maydell
                    comp = (opcode - 0x8) * 2 + u;
8113 94b6c911 Peter Maydell
                    /* ...but LE, LT are implemented as reverse GE, GT */
8114 94b6c911 Peter Maydell
                    reverse = (comp > 2);
8115 94b6c911 Peter Maydell
                    if (reverse) {
8116 94b6c911 Peter Maydell
                        comp = 4 - comp;
8117 94b6c911 Peter Maydell
                    }
8118 94b6c911 Peter Maydell
                    genfn = fns[comp][size];
8119 94b6c911 Peter Maydell
                    if (reverse) {
8120 94b6c911 Peter Maydell
                        genfn(tcg_res, tcg_zero, tcg_op);
8121 94b6c911 Peter Maydell
                    } else {
8122 94b6c911 Peter Maydell
                        genfn(tcg_res, tcg_op, tcg_zero);
8123 94b6c911 Peter Maydell
                    }
8124 94b6c911 Peter Maydell
                    tcg_temp_free_i32(tcg_zero);
8125 94b6c911 Peter Maydell
                    break;
8126 94b6c911 Peter Maydell
                }
8127 94b6c911 Peter Maydell
                case 0xb: /* ABS, NEG */
8128 94b6c911 Peter Maydell
                    if (u) {
8129 94b6c911 Peter Maydell
                        TCGv_i32 tcg_zero = tcg_const_i32(0);
8130 94b6c911 Peter Maydell
                        if (size) {
8131 94b6c911 Peter Maydell
                            gen_helper_neon_sub_u16(tcg_res, tcg_zero, tcg_op);
8132 94b6c911 Peter Maydell
                        } else {
8133 94b6c911 Peter Maydell
                            gen_helper_neon_sub_u8(tcg_res, tcg_zero, tcg_op);
8134 94b6c911 Peter Maydell
                        }
8135 94b6c911 Peter Maydell
                        tcg_temp_free_i32(tcg_zero);
8136 94b6c911 Peter Maydell
                    } else {
8137 94b6c911 Peter Maydell
                        if (size) {
8138 94b6c911 Peter Maydell
                            gen_helper_neon_abs_s16(tcg_res, tcg_op);
8139 94b6c911 Peter Maydell
                        } else {
8140 94b6c911 Peter Maydell
                            gen_helper_neon_abs_s8(tcg_res, tcg_op);
8141 94b6c911 Peter Maydell
                        }
8142 94b6c911 Peter Maydell
                    }
8143 94b6c911 Peter Maydell
                    break;
8144 94b6c911 Peter Maydell
                default:
8145 94b6c911 Peter Maydell
                    g_assert_not_reached();
8146 94b6c911 Peter Maydell
                }
8147 94b6c911 Peter Maydell
            }
8148 94b6c911 Peter Maydell
8149 94b6c911 Peter Maydell
            write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8150 94b6c911 Peter Maydell
8151 94b6c911 Peter Maydell
            tcg_temp_free_i32(tcg_res);
8152 94b6c911 Peter Maydell
            tcg_temp_free_i32(tcg_op);
8153 94b6c911 Peter Maydell
        }
8154 94b6c911 Peter Maydell
    }
8155 94b6c911 Peter Maydell
    if (!is_q) {
8156 94b6c911 Peter Maydell
        clear_vec_high(s, rd);
8157 94b6c911 Peter Maydell
    }
8158 384b26fb Alex Bennée
}
8159 384b26fb Alex Bennée
8160 9f82e0ff Peter Maydell
/* C3.6.13 AdvSIMD scalar x indexed element
8161 9f82e0ff Peter Maydell
 *  31 30  29 28       24 23  22 21  20  19  16 15 12  11  10 9    5 4    0
8162 9f82e0ff Peter Maydell
 * +-----+---+-----------+------+---+---+------+-----+---+---+------+------+
8163 9f82e0ff Peter Maydell
 * | 0 1 | U | 1 1 1 1 1 | size | L | M |  Rm  | opc | H | 0 |  Rn  |  Rd  |
8164 9f82e0ff Peter Maydell
 * +-----+---+-----------+------+---+---+------+-----+---+---+------+------+
8165 9f82e0ff Peter Maydell
 * C3.6.18 AdvSIMD vector x indexed element
8166 384b26fb Alex Bennée
 *   31  30  29 28       24 23  22 21  20  19  16 15 12  11  10 9    5 4    0
8167 384b26fb Alex Bennée
 * +---+---+---+-----------+------+---+---+------+-----+---+---+------+------+
8168 384b26fb Alex Bennée
 * | 0 | Q | U | 0 1 1 1 1 | size | L | M |  Rm  | opc | H | 0 |  Rn  |  Rd  |
8169 384b26fb Alex Bennée
 * +---+---+---+-----------+------+---+---+------+-----+---+---+------+------+
8170 384b26fb Alex Bennée
 */
8171 9f82e0ff Peter Maydell
static void disas_simd_indexed(DisasContext *s, uint32_t insn)
8172 384b26fb Alex Bennée
{
8173 f5e51e7f Peter Maydell
    /* This encoding has two kinds of instruction:
8174 f5e51e7f Peter Maydell
     *  normal, where we perform elt x idxelt => elt for each
8175 f5e51e7f Peter Maydell
     *     element in the vector
8176 f5e51e7f Peter Maydell
     *  long, where we perform elt x idxelt and generate a result of
8177 f5e51e7f Peter Maydell
     *     double the width of the input element
8178 f5e51e7f Peter Maydell
     * The long ops have a 'part' specifier (ie come in INSN, INSN2 pairs).
8179 f5e51e7f Peter Maydell
     */
8180 9f82e0ff Peter Maydell
    bool is_scalar = extract32(insn, 28, 1);
8181 f5e51e7f Peter Maydell
    bool is_q = extract32(insn, 30, 1);
8182 f5e51e7f Peter Maydell
    bool u = extract32(insn, 29, 1);
8183 f5e51e7f Peter Maydell
    int size = extract32(insn, 22, 2);
8184 f5e51e7f Peter Maydell
    int l = extract32(insn, 21, 1);
8185 f5e51e7f Peter Maydell
    int m = extract32(insn, 20, 1);
8186 f5e51e7f Peter Maydell
    /* Note that the Rm field here is only 4 bits, not 5 as it usually is */
8187 f5e51e7f Peter Maydell
    int rm = extract32(insn, 16, 4);
8188 f5e51e7f Peter Maydell
    int opcode = extract32(insn, 12, 4);
8189 f5e51e7f Peter Maydell
    int h = extract32(insn, 11, 1);
8190 f5e51e7f Peter Maydell
    int rn = extract32(insn, 5, 5);
8191 f5e51e7f Peter Maydell
    int rd = extract32(insn, 0, 5);
8192 f5e51e7f Peter Maydell
    bool is_long = false;
8193 f5e51e7f Peter Maydell
    bool is_fp = false;
8194 f5e51e7f Peter Maydell
    int index;
8195 f5e51e7f Peter Maydell
    TCGv_ptr fpst;
8196 f5e51e7f Peter Maydell
8197 f5e51e7f Peter Maydell
    switch (opcode) {
8198 f5e51e7f Peter Maydell
    case 0x0: /* MLA */
8199 f5e51e7f Peter Maydell
    case 0x4: /* MLS */
8200 9f82e0ff Peter Maydell
        if (!u || is_scalar) {
8201 f5e51e7f Peter Maydell
            unallocated_encoding(s);
8202 f5e51e7f Peter Maydell
            return;
8203 f5e51e7f Peter Maydell
        }
8204 f5e51e7f Peter Maydell
        break;
8205 f5e51e7f Peter Maydell
    case 0x2: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
8206 f5e51e7f Peter Maydell
    case 0x6: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
8207 f5e51e7f Peter Maydell
    case 0xa: /* SMULL, SMULL2, UMULL, UMULL2 */
8208 9f82e0ff Peter Maydell
        if (is_scalar) {
8209 9f82e0ff Peter Maydell
            unallocated_encoding(s);
8210 9f82e0ff Peter Maydell
            return;
8211 9f82e0ff Peter Maydell
        }
8212 f5e51e7f Peter Maydell
        is_long = true;
8213 f5e51e7f Peter Maydell
        break;
8214 f5e51e7f Peter Maydell
    case 0x3: /* SQDMLAL, SQDMLAL2 */
8215 f5e51e7f Peter Maydell
    case 0x7: /* SQDMLSL, SQDMLSL2 */
8216 f5e51e7f Peter Maydell
    case 0xb: /* SQDMULL, SQDMULL2 */
8217 f5e51e7f Peter Maydell
        is_long = true;
8218 f5e51e7f Peter Maydell
        /* fall through */
8219 f5e51e7f Peter Maydell
    case 0xc: /* SQDMULH */
8220 f5e51e7f Peter Maydell
    case 0xd: /* SQRDMULH */
8221 f5e51e7f Peter Maydell
        if (u) {
8222 f5e51e7f Peter Maydell
            unallocated_encoding(s);
8223 f5e51e7f Peter Maydell
            return;
8224 f5e51e7f Peter Maydell
        }
8225 f5e51e7f Peter Maydell
        break;
8226 9f82e0ff Peter Maydell
    case 0x8: /* MUL */
8227 9f82e0ff Peter Maydell
        if (u || is_scalar) {
8228 9f82e0ff Peter Maydell
            unallocated_encoding(s);
8229 9f82e0ff Peter Maydell
            return;
8230 9f82e0ff Peter Maydell
        }
8231 9f82e0ff Peter Maydell
        break;
8232 f5e51e7f Peter Maydell
    case 0x1: /* FMLA */
8233 f5e51e7f Peter Maydell
    case 0x5: /* FMLS */
8234 f5e51e7f Peter Maydell
        if (u) {
8235 f5e51e7f Peter Maydell
            unallocated_encoding(s);
8236 f5e51e7f Peter Maydell
            return;
8237 f5e51e7f Peter Maydell
        }
8238 f5e51e7f Peter Maydell
        /* fall through */
8239 f5e51e7f Peter Maydell
    case 0x9: /* FMUL, FMULX */
8240 f5e51e7f Peter Maydell
        if (!extract32(size, 1, 1)) {
8241 f5e51e7f Peter Maydell
            unallocated_encoding(s);
8242 f5e51e7f Peter Maydell
            return;
8243 f5e51e7f Peter Maydell
        }
8244 f5e51e7f Peter Maydell
        is_fp = true;
8245 f5e51e7f Peter Maydell
        break;
8246 f5e51e7f Peter Maydell
    default:
8247 f5e51e7f Peter Maydell
        unallocated_encoding(s);
8248 f5e51e7f Peter Maydell
        return;
8249 f5e51e7f Peter Maydell
    }
8250 f5e51e7f Peter Maydell
8251 f5e51e7f Peter Maydell
    if (is_fp) {
8252 f5e51e7f Peter Maydell
        /* low bit of size indicates single/double */
8253 f5e51e7f Peter Maydell
        size = extract32(size, 0, 1) ? 3 : 2;
8254 f5e51e7f Peter Maydell
        if (size == 2) {
8255 f5e51e7f Peter Maydell
            index = h << 1 | l;
8256 f5e51e7f Peter Maydell
        } else {
8257 f5e51e7f Peter Maydell
            if (l || !is_q) {
8258 f5e51e7f Peter Maydell
                unallocated_encoding(s);
8259 f5e51e7f Peter Maydell
                return;
8260 f5e51e7f Peter Maydell
            }
8261 f5e51e7f Peter Maydell
            index = h;
8262 f5e51e7f Peter Maydell
        }
8263 f5e51e7f Peter Maydell
        rm |= (m << 4);
8264 f5e51e7f Peter Maydell
    } else {
8265 f5e51e7f Peter Maydell
        switch (size) {
8266 f5e51e7f Peter Maydell
        case 1:
8267 f5e51e7f Peter Maydell
            index = h << 2 | l << 1 | m;
8268 f5e51e7f Peter Maydell
            break;
8269 f5e51e7f Peter Maydell
        case 2:
8270 f5e51e7f Peter Maydell
            index = h << 1 | l;
8271 f5e51e7f Peter Maydell
            rm |= (m << 4);
8272 f5e51e7f Peter Maydell
            break;
8273 f5e51e7f Peter Maydell
        default:
8274 f5e51e7f Peter Maydell
            unallocated_encoding(s);
8275 f5e51e7f Peter Maydell
            return;
8276 f5e51e7f Peter Maydell
        }
8277 f5e51e7f Peter Maydell
    }
8278 f5e51e7f Peter Maydell
8279 f5e51e7f Peter Maydell
    if (is_fp) {
8280 f5e51e7f Peter Maydell
        fpst = get_fpstatus_ptr();
8281 f5e51e7f Peter Maydell
    } else {
8282 f5e51e7f Peter Maydell
        TCGV_UNUSED_PTR(fpst);
8283 f5e51e7f Peter Maydell
    }
8284 f5e51e7f Peter Maydell
8285 f5e51e7f Peter Maydell
    if (size == 3) {
8286 f5e51e7f Peter Maydell
        TCGv_i64 tcg_idx = tcg_temp_new_i64();
8287 f5e51e7f Peter Maydell
        int pass;
8288 f5e51e7f Peter Maydell
8289 f5e51e7f Peter Maydell
        assert(is_fp && is_q && !is_long);
8290 f5e51e7f Peter Maydell
8291 f5e51e7f Peter Maydell
        read_vec_element(s, tcg_idx, rm, index, MO_64);
8292 f5e51e7f Peter Maydell
8293 9f82e0ff Peter Maydell
        for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
8294 f5e51e7f Peter Maydell
            TCGv_i64 tcg_op = tcg_temp_new_i64();
8295 f5e51e7f Peter Maydell
            TCGv_i64 tcg_res = tcg_temp_new_i64();
8296 f5e51e7f Peter Maydell
8297 f5e51e7f Peter Maydell
            read_vec_element(s, tcg_op, rn, pass, MO_64);
8298 f5e51e7f Peter Maydell
8299 f5e51e7f Peter Maydell
            switch (opcode) {
8300 f5e51e7f Peter Maydell
            case 0x5: /* FMLS */
8301 f5e51e7f Peter Maydell
                /* As usual for ARM, separate negation for fused multiply-add */
8302 f5e51e7f Peter Maydell
                gen_helper_vfp_negd(tcg_op, tcg_op);
8303 f5e51e7f Peter Maydell
                /* fall through */
8304 f5e51e7f Peter Maydell
            case 0x1: /* FMLA */
8305 f5e51e7f Peter Maydell
                read_vec_element(s, tcg_res, rd, pass, MO_64);
8306 f5e51e7f Peter Maydell
                gen_helper_vfp_muladdd(tcg_res, tcg_op, tcg_idx, tcg_res, fpst);
8307 f5e51e7f Peter Maydell
                break;
8308 f5e51e7f Peter Maydell
            case 0x9: /* FMUL, FMULX */
8309 f5e51e7f Peter Maydell
                if (u) {
8310 f5e51e7f Peter Maydell
                    gen_helper_vfp_mulxd(tcg_res, tcg_op, tcg_idx, fpst);
8311 f5e51e7f Peter Maydell
                } else {
8312 f5e51e7f Peter Maydell
                    gen_helper_vfp_muld(tcg_res, tcg_op, tcg_idx, fpst);
8313 f5e51e7f Peter Maydell
                }
8314 f5e51e7f Peter Maydell
                break;
8315 f5e51e7f Peter Maydell
            default:
8316 f5e51e7f Peter Maydell
                g_assert_not_reached();
8317 f5e51e7f Peter Maydell
            }
8318 f5e51e7f Peter Maydell
8319 f5e51e7f Peter Maydell
            write_vec_element(s, tcg_res, rd, pass, MO_64);
8320 f5e51e7f Peter Maydell
            tcg_temp_free_i64(tcg_op);
8321 f5e51e7f Peter Maydell
            tcg_temp_free_i64(tcg_res);
8322 f5e51e7f Peter Maydell
        }
8323 f5e51e7f Peter Maydell
8324 9f82e0ff Peter Maydell
        if (is_scalar) {
8325 9f82e0ff Peter Maydell
            clear_vec_high(s, rd);
8326 9f82e0ff Peter Maydell
        }
8327 9f82e0ff Peter Maydell
8328 f5e51e7f Peter Maydell
        tcg_temp_free_i64(tcg_idx);
8329 f5e51e7f Peter Maydell
    } else if (!is_long) {
8330 9f82e0ff Peter Maydell
        /* 32 bit floating point, or 16 or 32 bit integer.
8331 9f82e0ff Peter Maydell
         * For the 16 bit scalar case we use the usual Neon helpers and
8332 9f82e0ff Peter Maydell
         * rely on the fact that 0 op 0 == 0 with no side effects.
8333 9f82e0ff Peter Maydell
         */
8334 f5e51e7f Peter Maydell
        TCGv_i32 tcg_idx = tcg_temp_new_i32();
8335 9f82e0ff Peter Maydell
        int pass, maxpasses;
8336 9f82e0ff Peter Maydell
8337 9f82e0ff Peter Maydell
        if (is_scalar) {
8338 9f82e0ff Peter Maydell
            maxpasses = 1;
8339 9f82e0ff Peter Maydell
        } else {
8340 9f82e0ff Peter Maydell
            maxpasses = is_q ? 4 : 2;
8341 9f82e0ff Peter Maydell
        }
8342 f5e51e7f Peter Maydell
8343 f5e51e7f Peter Maydell
        read_vec_element_i32(s, tcg_idx, rm, index, size);
8344 f5e51e7f Peter Maydell
8345 9f82e0ff Peter Maydell
        if (size == 1 && !is_scalar) {
8346 f5e51e7f Peter Maydell
            /* The simplest way to handle the 16x16 indexed ops is to duplicate
8347 f5e51e7f Peter Maydell
             * the index into both halves of the 32 bit tcg_idx and then use
8348 f5e51e7f Peter Maydell
             * the usual Neon helpers.
8349 f5e51e7f Peter Maydell
             */
8350 f5e51e7f Peter Maydell
            tcg_gen_deposit_i32(tcg_idx, tcg_idx, tcg_idx, 16, 16);
8351 f5e51e7f Peter Maydell
        }
8352 f5e51e7f Peter Maydell
8353 9f82e0ff Peter Maydell
        for (pass = 0; pass < maxpasses; pass++) {
8354 f5e51e7f Peter Maydell
            TCGv_i32 tcg_op = tcg_temp_new_i32();
8355 f5e51e7f Peter Maydell
            TCGv_i32 tcg_res = tcg_temp_new_i32();
8356 f5e51e7f Peter Maydell
8357 9f82e0ff Peter Maydell
            read_vec_element_i32(s, tcg_op, rn, pass, is_scalar ? size : MO_32);
8358 f5e51e7f Peter Maydell
8359 f5e51e7f Peter Maydell
            switch (opcode) {
8360 f5e51e7f Peter Maydell
            case 0x0: /* MLA */
8361 f5e51e7f Peter Maydell
            case 0x4: /* MLS */
8362 f5e51e7f Peter Maydell
            case 0x8: /* MUL */
8363 f5e51e7f Peter Maydell
            {
8364 f5e51e7f Peter Maydell
                static NeonGenTwoOpFn * const fns[2][2] = {
8365 f5e51e7f Peter Maydell
                    { gen_helper_neon_add_u16, gen_helper_neon_sub_u16 },
8366 f5e51e7f Peter Maydell
                    { tcg_gen_add_i32, tcg_gen_sub_i32 },
8367 f5e51e7f Peter Maydell
                };
8368 f5e51e7f Peter Maydell
                NeonGenTwoOpFn *genfn;
8369 f5e51e7f Peter Maydell
                bool is_sub = opcode == 0x4;
8370 f5e51e7f Peter Maydell
8371 f5e51e7f Peter Maydell
                if (size == 1) {
8372 f5e51e7f Peter Maydell
                    gen_helper_neon_mul_u16(tcg_res, tcg_op, tcg_idx);
8373 f5e51e7f Peter Maydell
                } else {
8374 f5e51e7f Peter Maydell
                    tcg_gen_mul_i32(tcg_res, tcg_op, tcg_idx);
8375 f5e51e7f Peter Maydell
                }
8376 f5e51e7f Peter Maydell
                if (opcode == 0x8) {
8377 f5e51e7f Peter Maydell
                    break;
8378 f5e51e7f Peter Maydell
                }
8379 f5e51e7f Peter Maydell
                read_vec_element_i32(s, tcg_op, rd, pass, MO_32);
8380 f5e51e7f Peter Maydell
                genfn = fns[size - 1][is_sub];
8381 f5e51e7f Peter Maydell
                genfn(tcg_res, tcg_op, tcg_res);
8382 f5e51e7f Peter Maydell
                break;
8383 f5e51e7f Peter Maydell
            }
8384 f5e51e7f Peter Maydell
            case 0x5: /* FMLS */
8385 f5e51e7f Peter Maydell
                /* As usual for ARM, separate negation for fused multiply-add */
8386 f5e51e7f Peter Maydell
                gen_helper_vfp_negs(tcg_op, tcg_op);
8387 f5e51e7f Peter Maydell
                /* fall through */
8388 f5e51e7f Peter Maydell
            case 0x1: /* FMLA */
8389 f5e51e7f Peter Maydell
                read_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8390 f5e51e7f Peter Maydell
                gen_helper_vfp_muladds(tcg_res, tcg_op, tcg_idx, tcg_res, fpst);
8391 f5e51e7f Peter Maydell
                break;
8392 f5e51e7f Peter Maydell
            case 0x9: /* FMUL, FMULX */
8393 f5e51e7f Peter Maydell
                if (u) {
8394 f5e51e7f Peter Maydell
                    gen_helper_vfp_mulxs(tcg_res, tcg_op, tcg_idx, fpst);
8395 f5e51e7f Peter Maydell
                } else {
8396 f5e51e7f Peter Maydell
                    gen_helper_vfp_muls(tcg_res, tcg_op, tcg_idx, fpst);
8397 f5e51e7f Peter Maydell
                }
8398 f5e51e7f Peter Maydell
                break;
8399 f5e51e7f Peter Maydell
            case 0xc: /* SQDMULH */
8400 f5e51e7f Peter Maydell
                if (size == 1) {
8401 f5e51e7f Peter Maydell
                    gen_helper_neon_qdmulh_s16(tcg_res, cpu_env,
8402 f5e51e7f Peter Maydell
                                               tcg_op, tcg_idx);
8403 f5e51e7f Peter Maydell
                } else {
8404 f5e51e7f Peter Maydell
                    gen_helper_neon_qdmulh_s32(tcg_res, cpu_env,
8405 f5e51e7f Peter Maydell
                                               tcg_op, tcg_idx);
8406 f5e51e7f Peter Maydell
                }
8407 f5e51e7f Peter Maydell
                break;
8408 f5e51e7f Peter Maydell
            case 0xd: /* SQRDMULH */
8409 f5e51e7f Peter Maydell
                if (size == 1) {
8410 f5e51e7f Peter Maydell
                    gen_helper_neon_qrdmulh_s16(tcg_res, cpu_env,
8411 f5e51e7f Peter Maydell
                                                tcg_op, tcg_idx);
8412 f5e51e7f Peter Maydell
                } else {
8413 f5e51e7f Peter Maydell
                    gen_helper_neon_qrdmulh_s32(tcg_res, cpu_env,
8414 f5e51e7f Peter Maydell
                                                tcg_op, tcg_idx);
8415 f5e51e7f Peter Maydell
                }
8416 f5e51e7f Peter Maydell
                break;
8417 f5e51e7f Peter Maydell
            default:
8418 f5e51e7f Peter Maydell
                g_assert_not_reached();
8419 f5e51e7f Peter Maydell
            }
8420 f5e51e7f Peter Maydell
8421 9f82e0ff Peter Maydell
            if (is_scalar) {
8422 9f82e0ff Peter Maydell
                write_fp_sreg(s, rd, tcg_res);
8423 9f82e0ff Peter Maydell
            } else {
8424 9f82e0ff Peter Maydell
                write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8425 9f82e0ff Peter Maydell
            }
8426 9f82e0ff Peter Maydell
8427 f5e51e7f Peter Maydell
            tcg_temp_free_i32(tcg_op);
8428 f5e51e7f Peter Maydell
            tcg_temp_free_i32(tcg_res);
8429 f5e51e7f Peter Maydell
        }
8430 f5e51e7f Peter Maydell
8431 f5e51e7f Peter Maydell
        tcg_temp_free_i32(tcg_idx);
8432 f5e51e7f Peter Maydell
8433 f5e51e7f Peter Maydell
        if (!is_q) {
8434 f5e51e7f Peter Maydell
            clear_vec_high(s, rd);
8435 f5e51e7f Peter Maydell
        }
8436 f5e51e7f Peter Maydell
    } else {
8437 f5e51e7f Peter Maydell
        /* long ops: 16x16->32 or 32x32->64 */
8438 c44ad1fd Peter Maydell
        TCGv_i64 tcg_res[2];
8439 c44ad1fd Peter Maydell
        int pass;
8440 c44ad1fd Peter Maydell
        bool satop = extract32(opcode, 0, 1);
8441 c44ad1fd Peter Maydell
        TCGMemOp memop = MO_32;
8442 c44ad1fd Peter Maydell
8443 c44ad1fd Peter Maydell
        if (satop || !u) {
8444 c44ad1fd Peter Maydell
            memop |= MO_SIGN;
8445 c44ad1fd Peter Maydell
        }
8446 c44ad1fd Peter Maydell
8447 c44ad1fd Peter Maydell
        if (size == 2) {
8448 c44ad1fd Peter Maydell
            TCGv_i64 tcg_idx = tcg_temp_new_i64();
8449 c44ad1fd Peter Maydell
8450 c44ad1fd Peter Maydell
            read_vec_element(s, tcg_idx, rm, index, memop);
8451 c44ad1fd Peter Maydell
8452 9f82e0ff Peter Maydell
            for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
8453 c44ad1fd Peter Maydell
                TCGv_i64 tcg_op = tcg_temp_new_i64();
8454 c44ad1fd Peter Maydell
                TCGv_i64 tcg_passres;
8455 9f82e0ff Peter Maydell
                int passelt;
8456 c44ad1fd Peter Maydell
8457 9f82e0ff Peter Maydell
                if (is_scalar) {
8458 9f82e0ff Peter Maydell
                    passelt = 0;
8459 9f82e0ff Peter Maydell
                } else {
8460 9f82e0ff Peter Maydell
                    passelt = pass + (is_q * 2);
8461 9f82e0ff Peter Maydell
                }
8462 9f82e0ff Peter Maydell
8463 9f82e0ff Peter Maydell
                read_vec_element(s, tcg_op, rn, passelt, memop);
8464 c44ad1fd Peter Maydell
8465 c44ad1fd Peter Maydell
                tcg_res[pass] = tcg_temp_new_i64();
8466 c44ad1fd Peter Maydell
8467 c44ad1fd Peter Maydell
                if (opcode == 0xa || opcode == 0xb) {
8468 c44ad1fd Peter Maydell
                    /* Non-accumulating ops */
8469 c44ad1fd Peter Maydell
                    tcg_passres = tcg_res[pass];
8470 c44ad1fd Peter Maydell
                } else {
8471 c44ad1fd Peter Maydell
                    tcg_passres = tcg_temp_new_i64();
8472 c44ad1fd Peter Maydell
                }
8473 c44ad1fd Peter Maydell
8474 c44ad1fd Peter Maydell
                tcg_gen_mul_i64(tcg_passres, tcg_op, tcg_idx);
8475 c44ad1fd Peter Maydell
                tcg_temp_free_i64(tcg_op);
8476 c44ad1fd Peter Maydell
8477 c44ad1fd Peter Maydell
                if (satop) {
8478 c44ad1fd Peter Maydell
                    /* saturating, doubling */
8479 c44ad1fd Peter Maydell
                    gen_helper_neon_addl_saturate_s64(tcg_passres, cpu_env,
8480 c44ad1fd Peter Maydell
                                                      tcg_passres, tcg_passres);
8481 c44ad1fd Peter Maydell
                }
8482 c44ad1fd Peter Maydell
8483 c44ad1fd Peter Maydell
                if (opcode == 0xa || opcode == 0xb) {
8484 c44ad1fd Peter Maydell
                    continue;
8485 c44ad1fd Peter Maydell
                }
8486 c44ad1fd Peter Maydell
8487 c44ad1fd Peter Maydell
                /* Accumulating op: handle accumulate step */
8488 c44ad1fd Peter Maydell
                read_vec_element(s, tcg_res[pass], rd, pass, MO_64);
8489 c44ad1fd Peter Maydell
8490 c44ad1fd Peter Maydell
                switch (opcode) {
8491 c44ad1fd Peter Maydell
                case 0x2: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
8492 c44ad1fd Peter Maydell
                    tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
8493 c44ad1fd Peter Maydell
                    break;
8494 c44ad1fd Peter Maydell
                case 0x6: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
8495 c44ad1fd Peter Maydell
                    tcg_gen_sub_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
8496 c44ad1fd Peter Maydell
                    break;
8497 c44ad1fd Peter Maydell
                case 0x7: /* SQDMLSL, SQDMLSL2 */
8498 c44ad1fd Peter Maydell
                    tcg_gen_neg_i64(tcg_passres, tcg_passres);
8499 c44ad1fd Peter Maydell
                    /* fall through */
8500 c44ad1fd Peter Maydell
                case 0x3: /* SQDMLAL, SQDMLAL2 */
8501 c44ad1fd Peter Maydell
                    gen_helper_neon_addl_saturate_s64(tcg_res[pass], cpu_env,
8502 c44ad1fd Peter Maydell
                                                      tcg_res[pass],
8503 c44ad1fd Peter Maydell
                                                      tcg_passres);
8504 c44ad1fd Peter Maydell
                    break;
8505 c44ad1fd Peter Maydell
                default:
8506 c44ad1fd Peter Maydell
                    g_assert_not_reached();
8507 c44ad1fd Peter Maydell
                }
8508 c44ad1fd Peter Maydell
                tcg_temp_free_i64(tcg_passres);
8509 c44ad1fd Peter Maydell
            }
8510 c44ad1fd Peter Maydell
            tcg_temp_free_i64(tcg_idx);
8511 9f82e0ff Peter Maydell
8512 9f82e0ff Peter Maydell
            if (is_scalar) {
8513 9f82e0ff Peter Maydell
                clear_vec_high(s, rd);
8514 9f82e0ff Peter Maydell
            }
8515 c44ad1fd Peter Maydell
        } else {
8516 c44ad1fd Peter Maydell
            TCGv_i32 tcg_idx = tcg_temp_new_i32();
8517 c44ad1fd Peter Maydell
8518 c44ad1fd Peter Maydell
            assert(size == 1);
8519 c44ad1fd Peter Maydell
            read_vec_element_i32(s, tcg_idx, rm, index, size);
8520 c44ad1fd Peter Maydell
8521 9f82e0ff Peter Maydell
            if (!is_scalar) {
8522 9f82e0ff Peter Maydell
                /* The simplest way to handle the 16x16 indexed ops is to
8523 9f82e0ff Peter Maydell
                 * duplicate the index into both halves of the 32 bit tcg_idx
8524 9f82e0ff Peter Maydell
                 * and then use the usual Neon helpers.
8525 9f82e0ff Peter Maydell
                 */
8526 9f82e0ff Peter Maydell
                tcg_gen_deposit_i32(tcg_idx, tcg_idx, tcg_idx, 16, 16);
8527 9f82e0ff Peter Maydell
            }
8528 c44ad1fd Peter Maydell
8529 9f82e0ff Peter Maydell
            for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
8530 c44ad1fd Peter Maydell
                TCGv_i32 tcg_op = tcg_temp_new_i32();
8531 c44ad1fd Peter Maydell
                TCGv_i64 tcg_passres;
8532 c44ad1fd Peter Maydell
8533 9f82e0ff Peter Maydell
                if (is_scalar) {
8534 9f82e0ff Peter Maydell
                    read_vec_element_i32(s, tcg_op, rn, pass, size);
8535 9f82e0ff Peter Maydell
                } else {
8536 9f82e0ff Peter Maydell
                    read_vec_element_i32(s, tcg_op, rn,
8537 9f82e0ff Peter Maydell
                                         pass + (is_q * 2), MO_32);
8538 9f82e0ff Peter Maydell
                }
8539 9f82e0ff Peter Maydell
8540 c44ad1fd Peter Maydell
                tcg_res[pass] = tcg_temp_new_i64();
8541 c44ad1fd Peter Maydell
8542 c44ad1fd Peter Maydell
                if (opcode == 0xa || opcode == 0xb) {
8543 c44ad1fd Peter Maydell
                    /* Non-accumulating ops */
8544 c44ad1fd Peter Maydell
                    tcg_passres = tcg_res[pass];
8545 c44ad1fd Peter Maydell
                } else {
8546 c44ad1fd Peter Maydell
                    tcg_passres = tcg_temp_new_i64();
8547 c44ad1fd Peter Maydell
                }
8548 c44ad1fd Peter Maydell
8549 c44ad1fd Peter Maydell
                if (memop & MO_SIGN) {
8550 c44ad1fd Peter Maydell
                    gen_helper_neon_mull_s16(tcg_passres, tcg_op, tcg_idx);
8551 c44ad1fd Peter Maydell
                } else {
8552 c44ad1fd Peter Maydell
                    gen_helper_neon_mull_u16(tcg_passres, tcg_op, tcg_idx);
8553 c44ad1fd Peter Maydell
                }
8554 c44ad1fd Peter Maydell
                if (satop) {
8555 c44ad1fd Peter Maydell
                    gen_helper_neon_addl_saturate_s32(tcg_passres, cpu_env,
8556 c44ad1fd Peter Maydell
                                                      tcg_passres, tcg_passres);
8557 c44ad1fd Peter Maydell
                }
8558 c44ad1fd Peter Maydell
                tcg_temp_free_i32(tcg_op);
8559 c44ad1fd Peter Maydell
8560 c44ad1fd Peter Maydell
                if (opcode == 0xa || opcode == 0xb) {
8561 c44ad1fd Peter Maydell
                    continue;
8562 c44ad1fd Peter Maydell
                }
8563 c44ad1fd Peter Maydell
8564 c44ad1fd Peter Maydell
                /* Accumulating op: handle accumulate step */
8565 c44ad1fd Peter Maydell
                read_vec_element(s, tcg_res[pass], rd, pass, MO_64);
8566 c44ad1fd Peter Maydell
8567 c44ad1fd Peter Maydell
                switch (opcode) {
8568 c44ad1fd Peter Maydell
                case 0x2: /* SMLAL, SMLAL2, UMLAL, UMLAL2 */
8569 c44ad1fd Peter Maydell
                    gen_helper_neon_addl_u32(tcg_res[pass], tcg_res[pass],
8570 c44ad1fd Peter Maydell
                                             tcg_passres);
8571 c44ad1fd Peter Maydell
                    break;
8572 c44ad1fd Peter Maydell
                case 0x6: /* SMLSL, SMLSL2, UMLSL, UMLSL2 */
8573 c44ad1fd Peter Maydell
                    gen_helper_neon_subl_u32(tcg_res[pass], tcg_res[pass],
8574 c44ad1fd Peter Maydell
                                             tcg_passres);
8575 c44ad1fd Peter Maydell
                    break;
8576 c44ad1fd Peter Maydell
                case 0x7: /* SQDMLSL, SQDMLSL2 */
8577 c44ad1fd Peter Maydell
                    gen_helper_neon_negl_u32(tcg_passres, tcg_passres);
8578 c44ad1fd Peter Maydell
                    /* fall through */
8579 c44ad1fd Peter Maydell
                case 0x3: /* SQDMLAL, SQDMLAL2 */
8580 c44ad1fd Peter Maydell
                    gen_helper_neon_addl_saturate_s32(tcg_res[pass], cpu_env,
8581 c44ad1fd Peter Maydell
                                                      tcg_res[pass],
8582 c44ad1fd Peter Maydell
                                                      tcg_passres);
8583 c44ad1fd Peter Maydell
                    break;
8584 c44ad1fd Peter Maydell
                default:
8585 c44ad1fd Peter Maydell
                    g_assert_not_reached();
8586 c44ad1fd Peter Maydell
                }
8587 c44ad1fd Peter Maydell
                tcg_temp_free_i64(tcg_passres);
8588 c44ad1fd Peter Maydell
            }
8589 c44ad1fd Peter Maydell
            tcg_temp_free_i32(tcg_idx);
8590 9f82e0ff Peter Maydell
8591 9f82e0ff Peter Maydell
            if (is_scalar) {
8592 9f82e0ff Peter Maydell
                tcg_gen_ext32u_i64(tcg_res[0], tcg_res[0]);
8593 9f82e0ff Peter Maydell
            }
8594 9f82e0ff Peter Maydell
        }
8595 9f82e0ff Peter Maydell
8596 9f82e0ff Peter Maydell
        if (is_scalar) {
8597 9f82e0ff Peter Maydell
            tcg_res[1] = tcg_const_i64(0);
8598 c44ad1fd Peter Maydell
        }
8599 c44ad1fd Peter Maydell
8600 c44ad1fd Peter Maydell
        for (pass = 0; pass < 2; pass++) {
8601 c44ad1fd Peter Maydell
            write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
8602 c44ad1fd Peter Maydell
            tcg_temp_free_i64(tcg_res[pass]);
8603 c44ad1fd Peter Maydell
        }
8604 f5e51e7f Peter Maydell
    }
8605 f5e51e7f Peter Maydell
8606 f5e51e7f Peter Maydell
    if (!TCGV_IS_UNUSED_PTR(fpst)) {
8607 f5e51e7f Peter Maydell
        tcg_temp_free_ptr(fpst);
8608 f5e51e7f Peter Maydell
    }
8609 384b26fb Alex Bennée
}
8610 384b26fb Alex Bennée
8611 384b26fb Alex Bennée
/* C3.6.19 Crypto AES
8612 384b26fb Alex Bennée
 *  31             24 23  22 21       17 16    12 11 10 9    5 4    0
8613 384b26fb Alex Bennée
 * +-----------------+------+-----------+--------+-----+------+------+
8614 384b26fb Alex Bennée
 * | 0 1 0 0 1 1 1 0 | size | 1 0 1 0 0 | opcode | 1 0 |  Rn  |  Rd  |
8615 384b26fb Alex Bennée
 * +-----------------+------+-----------+--------+-----+------+------+
8616 384b26fb Alex Bennée
 */
8617 384b26fb Alex Bennée
static void disas_crypto_aes(DisasContext *s, uint32_t insn)
8618 384b26fb Alex Bennée
{
8619 384b26fb Alex Bennée
    unsupported_encoding(s, insn);
8620 384b26fb Alex Bennée
}
8621 384b26fb Alex Bennée
8622 384b26fb Alex Bennée
/* C3.6.20 Crypto three-reg SHA
8623 384b26fb Alex Bennée
 *  31             24 23  22  21 20  16  15 14    12 11 10 9    5 4    0
8624 384b26fb Alex Bennée
 * +-----------------+------+---+------+---+--------+-----+------+------+
8625 384b26fb Alex Bennée
 * | 0 1 0 1 1 1 1 0 | size | 0 |  Rm  | 0 | opcode | 0 0 |  Rn  |  Rd  |
8626 384b26fb Alex Bennée
 * +-----------------+------+---+------+---+--------+-----+------+------+
8627 384b26fb Alex Bennée
 */
8628 384b26fb Alex Bennée
static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
8629 384b26fb Alex Bennée
{
8630 384b26fb Alex Bennée
    unsupported_encoding(s, insn);
8631 384b26fb Alex Bennée
}
8632 384b26fb Alex Bennée
8633 384b26fb Alex Bennée
/* C3.6.21 Crypto two-reg SHA
8634 384b26fb Alex Bennée
 *  31             24 23  22 21       17 16    12 11 10 9    5 4    0
8635 384b26fb Alex Bennée
 * +-----------------+------+-----------+--------+-----+------+------+
8636 384b26fb Alex Bennée
 * | 0 1 0 1 1 1 1 0 | size | 1 0 1 0 0 | opcode | 1 0 |  Rn  |  Rd  |
8637 384b26fb Alex Bennée
 * +-----------------+------+-----------+--------+-----+------+------+
8638 384b26fb Alex Bennée
 */
8639 384b26fb Alex Bennée
static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn)
8640 384b26fb Alex Bennée
{
8641 384b26fb Alex Bennée
    unsupported_encoding(s, insn);
8642 384b26fb Alex Bennée
}
8643 384b26fb Alex Bennée
8644 384b26fb Alex Bennée
/* C3.6 Data processing - SIMD, inc Crypto
8645 384b26fb Alex Bennée
 *
8646 384b26fb Alex Bennée
 * As the decode gets a little complex we are using a table based
8647 384b26fb Alex Bennée
 * approach for this part of the decode.
8648 384b26fb Alex Bennée
 */
8649 384b26fb Alex Bennée
static const AArch64DecodeTable data_proc_simd[] = {
8650 384b26fb Alex Bennée
    /* pattern  ,  mask     ,  fn                        */
8651 384b26fb Alex Bennée
    { 0x0e200400, 0x9f200400, disas_simd_three_reg_same },
8652 384b26fb Alex Bennée
    { 0x0e200000, 0x9f200c00, disas_simd_three_reg_diff },
8653 384b26fb Alex Bennée
    { 0x0e200800, 0x9f3e0c00, disas_simd_two_reg_misc },
8654 384b26fb Alex Bennée
    { 0x0e300800, 0x9f3e0c00, disas_simd_across_lanes },
8655 384b26fb Alex Bennée
    { 0x0e000400, 0x9fe08400, disas_simd_copy },
8656 9f82e0ff Peter Maydell
    { 0x0f000000, 0x9f000400, disas_simd_indexed }, /* vector indexed */
8657 384b26fb Alex Bennée
    /* simd_mod_imm decode is a subset of simd_shift_imm, so must precede it */
8658 384b26fb Alex Bennée
    { 0x0f000400, 0x9ff80400, disas_simd_mod_imm },
8659 384b26fb Alex Bennée
    { 0x0f000400, 0x9f800400, disas_simd_shift_imm },
8660 384b26fb Alex Bennée
    { 0x0e000000, 0xbf208c00, disas_simd_tb },
8661 384b26fb Alex Bennée
    { 0x0e000800, 0xbf208c00, disas_simd_zip_trn },
8662 384b26fb Alex Bennée
    { 0x2e000000, 0xbf208400, disas_simd_ext },
8663 384b26fb Alex Bennée
    { 0x5e200400, 0xdf200400, disas_simd_scalar_three_reg_same },
8664 384b26fb Alex Bennée
    { 0x5e200000, 0xdf200c00, disas_simd_scalar_three_reg_diff },
8665 384b26fb Alex Bennée
    { 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc },
8666 384b26fb Alex Bennée
    { 0x5e300800, 0xdf3e0c00, disas_simd_scalar_pairwise },
8667 384b26fb Alex Bennée
    { 0x5e000400, 0xdfe08400, disas_simd_scalar_copy },
8668 9f82e0ff Peter Maydell
    { 0x5f000000, 0xdf000400, disas_simd_indexed }, /* scalar indexed */
8669 384b26fb Alex Bennée
    { 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm },
8670 384b26fb Alex Bennée
    { 0x4e280800, 0xff3e0c00, disas_crypto_aes },
8671 384b26fb Alex Bennée
    { 0x5e000000, 0xff208c00, disas_crypto_three_reg_sha },
8672 384b26fb Alex Bennée
    { 0x5e280800, 0xff3e0c00, disas_crypto_two_reg_sha },
8673 384b26fb Alex Bennée
    { 0x00000000, 0x00000000, NULL }
8674 384b26fb Alex Bennée
};
8675 384b26fb Alex Bennée
8676 faa0ba46 Peter Maydell
static void disas_data_proc_simd(DisasContext *s, uint32_t insn)
8677 faa0ba46 Peter Maydell
{
8678 faa0ba46 Peter Maydell
    /* Note that this is called with all non-FP cases from
8679 faa0ba46 Peter Maydell
     * table C3-6 so it must UNDEF for entries not specifically
8680 faa0ba46 Peter Maydell
     * allocated to instructions in that table.
8681 faa0ba46 Peter Maydell
     */
8682 384b26fb Alex Bennée
    AArch64DecodeFn *fn = lookup_disas_fn(&data_proc_simd[0], insn);
8683 384b26fb Alex Bennée
    if (fn) {
8684 384b26fb Alex Bennée
        fn(s, insn);
8685 384b26fb Alex Bennée
    } else {
8686 384b26fb Alex Bennée
        unallocated_encoding(s);
8687 384b26fb Alex Bennée
    }
8688 faa0ba46 Peter Maydell
}
8689 faa0ba46 Peter Maydell
8690 ad7ee8a2 Claudio Fontana
/* C3.6 Data processing - SIMD and floating point */
8691 ad7ee8a2 Claudio Fontana
static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
8692 ad7ee8a2 Claudio Fontana
{
8693 faa0ba46 Peter Maydell
    if (extract32(insn, 28, 1) == 1 && extract32(insn, 30, 1) == 0) {
8694 faa0ba46 Peter Maydell
        disas_data_proc_fp(s, insn);
8695 faa0ba46 Peter Maydell
    } else {
8696 faa0ba46 Peter Maydell
        /* SIMD, including crypto */
8697 faa0ba46 Peter Maydell
        disas_data_proc_simd(s, insn);
8698 faa0ba46 Peter Maydell
    }
8699 ad7ee8a2 Claudio Fontana
}
8700 ad7ee8a2 Claudio Fontana
8701 ad7ee8a2 Claudio Fontana
/* C3.1 A64 instruction index by encoding */
8702 40f860cd Peter Maydell
static void disas_a64_insn(CPUARMState *env, DisasContext *s)
8703 14ade10f Alexander Graf
{
8704 14ade10f Alexander Graf
    uint32_t insn;
8705 14ade10f Alexander Graf
8706 14ade10f Alexander Graf
    insn = arm_ldl_code(env, s->pc, s->bswap_code);
8707 14ade10f Alexander Graf
    s->insn = insn;
8708 14ade10f Alexander Graf
    s->pc += 4;
8709 14ade10f Alexander Graf
8710 ad7ee8a2 Claudio Fontana
    switch (extract32(insn, 25, 4)) {
8711 ad7ee8a2 Claudio Fontana
    case 0x0: case 0x1: case 0x2: case 0x3: /* UNALLOCATED */
8712 14ade10f Alexander Graf
        unallocated_encoding(s);
8713 14ade10f Alexander Graf
        break;
8714 ad7ee8a2 Claudio Fontana
    case 0x8: case 0x9: /* Data processing - immediate */
8715 ad7ee8a2 Claudio Fontana
        disas_data_proc_imm(s, insn);
8716 ad7ee8a2 Claudio Fontana
        break;
8717 ad7ee8a2 Claudio Fontana
    case 0xa: case 0xb: /* Branch, exception generation and system insns */
8718 ad7ee8a2 Claudio Fontana
        disas_b_exc_sys(s, insn);
8719 ad7ee8a2 Claudio Fontana
        break;
8720 ad7ee8a2 Claudio Fontana
    case 0x4:
8721 ad7ee8a2 Claudio Fontana
    case 0x6:
8722 ad7ee8a2 Claudio Fontana
    case 0xc:
8723 ad7ee8a2 Claudio Fontana
    case 0xe:      /* Loads and stores */
8724 ad7ee8a2 Claudio Fontana
        disas_ldst(s, insn);
8725 ad7ee8a2 Claudio Fontana
        break;
8726 ad7ee8a2 Claudio Fontana
    case 0x5:
8727 ad7ee8a2 Claudio Fontana
    case 0xd:      /* Data processing - register */
8728 ad7ee8a2 Claudio Fontana
        disas_data_proc_reg(s, insn);
8729 ad7ee8a2 Claudio Fontana
        break;
8730 ad7ee8a2 Claudio Fontana
    case 0x7:
8731 ad7ee8a2 Claudio Fontana
    case 0xf:      /* Data processing - SIMD and floating point */
8732 ad7ee8a2 Claudio Fontana
        disas_data_proc_simd_fp(s, insn);
8733 ad7ee8a2 Claudio Fontana
        break;
8734 ad7ee8a2 Claudio Fontana
    default:
8735 ad7ee8a2 Claudio Fontana
        assert(FALSE); /* all 15 cases should be handled above */
8736 ad7ee8a2 Claudio Fontana
        break;
8737 14ade10f Alexander Graf
    }
8738 11e169de Alexander Graf
8739 11e169de Alexander Graf
    /* if we allocated any temporaries, free them here */
8740 11e169de Alexander Graf
    free_tmp_a64(s);
8741 40f860cd Peter Maydell
}
8742 14ade10f Alexander Graf
8743 40f860cd Peter Maydell
void gen_intermediate_code_internal_a64(ARMCPU *cpu,
8744 40f860cd Peter Maydell
                                        TranslationBlock *tb,
8745 40f860cd Peter Maydell
                                        bool search_pc)
8746 40f860cd Peter Maydell
{
8747 40f860cd Peter Maydell
    CPUState *cs = CPU(cpu);
8748 40f860cd Peter Maydell
    CPUARMState *env = &cpu->env;
8749 40f860cd Peter Maydell
    DisasContext dc1, *dc = &dc1;
8750 40f860cd Peter Maydell
    CPUBreakpoint *bp;
8751 40f860cd Peter Maydell
    uint16_t *gen_opc_end;
8752 40f860cd Peter Maydell
    int j, lj;
8753 40f860cd Peter Maydell
    target_ulong pc_start;
8754 40f860cd Peter Maydell
    target_ulong next_page_start;
8755 40f860cd Peter Maydell
    int num_insns;
8756 40f860cd Peter Maydell
    int max_insns;
8757 40f860cd Peter Maydell
8758 40f860cd Peter Maydell
    pc_start = tb->pc;
8759 40f860cd Peter Maydell
8760 40f860cd Peter Maydell
    dc->tb = tb;
8761 40f860cd Peter Maydell
8762 40f860cd Peter Maydell
    gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
8763 40f860cd Peter Maydell
8764 40f860cd Peter Maydell
    dc->is_jmp = DISAS_NEXT;
8765 40f860cd Peter Maydell
    dc->pc = pc_start;
8766 40f860cd Peter Maydell
    dc->singlestep_enabled = cs->singlestep_enabled;
8767 40f860cd Peter Maydell
    dc->condjmp = 0;
8768 40f860cd Peter Maydell
8769 40f860cd Peter Maydell
    dc->aarch64 = 1;
8770 40f860cd Peter Maydell
    dc->thumb = 0;
8771 40f860cd Peter Maydell
    dc->bswap_code = 0;
8772 40f860cd Peter Maydell
    dc->condexec_mask = 0;
8773 40f860cd Peter Maydell
    dc->condexec_cond = 0;
8774 40f860cd Peter Maydell
#if !defined(CONFIG_USER_ONLY)
8775 40f860cd Peter Maydell
    dc->user = 0;
8776 40f860cd Peter Maydell
#endif
8777 40f860cd Peter Maydell
    dc->vfp_enabled = 0;
8778 40f860cd Peter Maydell
    dc->vec_len = 0;
8779 40f860cd Peter Maydell
    dc->vec_stride = 0;
8780 60322b39 Peter Maydell
    dc->cp_regs = cpu->cp_regs;
8781 60322b39 Peter Maydell
    dc->current_pl = arm_current_pl(env);
8782 40f860cd Peter Maydell
8783 11e169de Alexander Graf
    init_tmp_a64_array(dc);
8784 11e169de Alexander Graf
8785 40f860cd Peter Maydell
    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
8786 40f860cd Peter Maydell
    lj = -1;
8787 40f860cd Peter Maydell
    num_insns = 0;
8788 40f860cd Peter Maydell
    max_insns = tb->cflags & CF_COUNT_MASK;
8789 40f860cd Peter Maydell
    if (max_insns == 0) {
8790 40f860cd Peter Maydell
        max_insns = CF_COUNT_MASK;
8791 40f860cd Peter Maydell
    }
8792 40f860cd Peter Maydell
8793 40f860cd Peter Maydell
    gen_tb_start();
8794 40f860cd Peter Maydell
8795 40f860cd Peter Maydell
    tcg_clear_temp_count();
8796 40f860cd Peter Maydell
8797 40f860cd Peter Maydell
    do {
8798 40f860cd Peter Maydell
        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
8799 40f860cd Peter Maydell
            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
8800 40f860cd Peter Maydell
                if (bp->pc == dc->pc) {
8801 40f860cd Peter Maydell
                    gen_exception_insn(dc, 0, EXCP_DEBUG);
8802 40f860cd Peter Maydell
                    /* Advance PC so that clearing the breakpoint will
8803 40f860cd Peter Maydell
                       invalidate this TB.  */
8804 40f860cd Peter Maydell
                    dc->pc += 2;
8805 40f860cd Peter Maydell
                    goto done_generating;
8806 40f860cd Peter Maydell
                }
8807 40f860cd Peter Maydell
            }
8808 40f860cd Peter Maydell
        }
8809 40f860cd Peter Maydell
8810 40f860cd Peter Maydell
        if (search_pc) {
8811 40f860cd Peter Maydell
            j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
8812 40f860cd Peter Maydell
            if (lj < j) {
8813 40f860cd Peter Maydell
                lj++;
8814 40f860cd Peter Maydell
                while (lj < j) {
8815 40f860cd Peter Maydell
                    tcg_ctx.gen_opc_instr_start[lj++] = 0;
8816 40f860cd Peter Maydell
                }
8817 40f860cd Peter Maydell
            }
8818 40f860cd Peter Maydell
            tcg_ctx.gen_opc_pc[lj] = dc->pc;
8819 40f860cd Peter Maydell
            tcg_ctx.gen_opc_instr_start[lj] = 1;
8820 40f860cd Peter Maydell
            tcg_ctx.gen_opc_icount[lj] = num_insns;
8821 40f860cd Peter Maydell
        }
8822 40f860cd Peter Maydell
8823 40f860cd Peter Maydell
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
8824 40f860cd Peter Maydell
            gen_io_start();
8825 40f860cd Peter Maydell
        }
8826 40f860cd Peter Maydell
8827 40f860cd Peter Maydell
        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
8828 40f860cd Peter Maydell
            tcg_gen_debug_insn_start(dc->pc);
8829 40f860cd Peter Maydell
        }
8830 40f860cd Peter Maydell
8831 40f860cd Peter Maydell
        disas_a64_insn(env, dc);
8832 40f860cd Peter Maydell
8833 40f860cd Peter Maydell
        if (tcg_check_temp_count()) {
8834 40f860cd Peter Maydell
            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
8835 40f860cd Peter Maydell
                    dc->pc);
8836 40f860cd Peter Maydell
        }
8837 40f860cd Peter Maydell
8838 40f860cd Peter Maydell
        /* Translation stops when a conditional branch is encountered.
8839 40f860cd Peter Maydell
         * Otherwise the subsequent code could get translated several times.
8840 40f860cd Peter Maydell
         * Also stop translation when a page boundary is reached.  This
8841 40f860cd Peter Maydell
         * ensures prefetch aborts occur at the right place.
8842 40f860cd Peter Maydell
         */
8843 40f860cd Peter Maydell
        num_insns++;
8844 40f860cd Peter Maydell
    } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
8845 40f860cd Peter Maydell
             !cs->singlestep_enabled &&
8846 40f860cd Peter Maydell
             !singlestep &&
8847 40f860cd Peter Maydell
             dc->pc < next_page_start &&
8848 40f860cd Peter Maydell
             num_insns < max_insns);
8849 40f860cd Peter Maydell
8850 40f860cd Peter Maydell
    if (tb->cflags & CF_LAST_IO) {
8851 40f860cd Peter Maydell
        gen_io_end();
8852 40f860cd Peter Maydell
    }
8853 40f860cd Peter Maydell
8854 40f860cd Peter Maydell
    if (unlikely(cs->singlestep_enabled) && dc->is_jmp != DISAS_EXC) {
8855 40f860cd Peter Maydell
        /* Note that this means single stepping WFI doesn't halt the CPU.
8856 40f860cd Peter Maydell
         * For conditional branch insns this is harmless unreachable code as
8857 40f860cd Peter Maydell
         * gen_goto_tb() has already handled emitting the debug exception
8858 40f860cd Peter Maydell
         * (and thus a tb-jump is not possible when singlestepping).
8859 40f860cd Peter Maydell
         */
8860 40f860cd Peter Maydell
        assert(dc->is_jmp != DISAS_TB_JUMP);
8861 40f860cd Peter Maydell
        if (dc->is_jmp != DISAS_JUMP) {
8862 40f860cd Peter Maydell
            gen_a64_set_pc_im(dc->pc);
8863 40f860cd Peter Maydell
        }
8864 40f860cd Peter Maydell
        gen_exception(EXCP_DEBUG);
8865 40f860cd Peter Maydell
    } else {
8866 40f860cd Peter Maydell
        switch (dc->is_jmp) {
8867 40f860cd Peter Maydell
        case DISAS_NEXT:
8868 40f860cd Peter Maydell
            gen_goto_tb(dc, 1, dc->pc);
8869 40f860cd Peter Maydell
            break;
8870 40f860cd Peter Maydell
        default:
8871 40f860cd Peter Maydell
        case DISAS_UPDATE:
8872 fea50522 Peter Maydell
            gen_a64_set_pc_im(dc->pc);
8873 fea50522 Peter Maydell
            /* fall through */
8874 fea50522 Peter Maydell
        case DISAS_JUMP:
8875 40f860cd Peter Maydell
            /* indicate that the hash table must be used to find the next TB */
8876 40f860cd Peter Maydell
            tcg_gen_exit_tb(0);
8877 40f860cd Peter Maydell
            break;
8878 40f860cd Peter Maydell
        case DISAS_TB_JUMP:
8879 40f860cd Peter Maydell
        case DISAS_EXC:
8880 40f860cd Peter Maydell
        case DISAS_SWI:
8881 40f860cd Peter Maydell
            break;
8882 40f860cd Peter Maydell
        case DISAS_WFI:
8883 40f860cd Peter Maydell
            /* This is a special case because we don't want to just halt the CPU
8884 40f860cd Peter Maydell
             * if trying to debug across a WFI.
8885 40f860cd Peter Maydell
             */
8886 40f860cd Peter Maydell
            gen_helper_wfi(cpu_env);
8887 40f860cd Peter Maydell
            break;
8888 40f860cd Peter Maydell
        }
8889 40f860cd Peter Maydell
    }
8890 40f860cd Peter Maydell
8891 40f860cd Peter Maydell
done_generating:
8892 40f860cd Peter Maydell
    gen_tb_end(tb, num_insns);
8893 40f860cd Peter Maydell
    *tcg_ctx.gen_opc_ptr = INDEX_op_end;
8894 40f860cd Peter Maydell
8895 40f860cd Peter Maydell
#ifdef DEBUG_DISAS
8896 40f860cd Peter Maydell
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
8897 40f860cd Peter Maydell
        qemu_log("----------------\n");
8898 40f860cd Peter Maydell
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
8899 40f860cd Peter Maydell
        log_target_disas(env, pc_start, dc->pc - pc_start,
8900 999b53ec Claudio Fontana
                         4 | (dc->bswap_code << 1));
8901 40f860cd Peter Maydell
        qemu_log("\n");
8902 40f860cd Peter Maydell
    }
8903 40f860cd Peter Maydell
#endif
8904 40f860cd Peter Maydell
    if (search_pc) {
8905 40f860cd Peter Maydell
        j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
8906 40f860cd Peter Maydell
        lj++;
8907 40f860cd Peter Maydell
        while (lj <= j) {
8908 40f860cd Peter Maydell
            tcg_ctx.gen_opc_instr_start[lj++] = 0;
8909 40f860cd Peter Maydell
        }
8910 40f860cd Peter Maydell
    } else {
8911 40f860cd Peter Maydell
        tb->size = dc->pc - pc_start;
8912 40f860cd Peter Maydell
        tb->icount = num_insns;
8913 14ade10f Alexander Graf
    }
8914 14ade10f Alexander Graf
}