xref: /qemu/target/arm/tcg/translate.c (revision 03a648c4)
1f0984d40SFabiano Rosas /*
2f0984d40SFabiano Rosas  *  ARM translation
3f0984d40SFabiano Rosas  *
4f0984d40SFabiano Rosas  *  Copyright (c) 2003 Fabrice Bellard
5f0984d40SFabiano Rosas  *  Copyright (c) 2005-2007 CodeSourcery
6f0984d40SFabiano Rosas  *  Copyright (c) 2007 OpenedHand, Ltd.
7f0984d40SFabiano Rosas  *
8f0984d40SFabiano Rosas  * This library is free software; you can redistribute it and/or
9f0984d40SFabiano Rosas  * modify it under the terms of the GNU Lesser General Public
10f0984d40SFabiano Rosas  * License as published by the Free Software Foundation; either
11f0984d40SFabiano Rosas  * version 2.1 of the License, or (at your option) any later version.
12f0984d40SFabiano Rosas  *
13f0984d40SFabiano Rosas  * This library is distributed in the hope that it will be useful,
14f0984d40SFabiano Rosas  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15f0984d40SFabiano Rosas  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16f0984d40SFabiano Rosas  * Lesser General Public License for more details.
17f0984d40SFabiano Rosas  *
18f0984d40SFabiano Rosas  * You should have received a copy of the GNU Lesser General Public
19f0984d40SFabiano Rosas  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20f0984d40SFabiano Rosas  */
21f0984d40SFabiano Rosas #include "qemu/osdep.h"
22f0984d40SFabiano Rosas 
23f0984d40SFabiano Rosas #include "cpu.h"
24f0984d40SFabiano Rosas #include "internals.h"
25f0984d40SFabiano Rosas #include "disas/disas.h"
26f0984d40SFabiano Rosas #include "exec/exec-all.h"
27f0984d40SFabiano Rosas #include "tcg/tcg-op.h"
28f0984d40SFabiano Rosas #include "tcg/tcg-op-gvec.h"
29f0984d40SFabiano Rosas #include "qemu/log.h"
30f0984d40SFabiano Rosas #include "qemu/bitops.h"
31f0984d40SFabiano Rosas #include "arm_ldst.h"
32f0984d40SFabiano Rosas #include "semihosting/semihost.h"
33f0984d40SFabiano Rosas #include "exec/helper-proto.h"
34f0984d40SFabiano Rosas #include "exec/helper-gen.h"
35f0984d40SFabiano Rosas #include "exec/log.h"
36f0984d40SFabiano Rosas #include "cpregs.h"
37f0984d40SFabiano Rosas 
38f0984d40SFabiano Rosas 
39f0984d40SFabiano Rosas #define ENABLE_ARCH_4T    arm_dc_feature(s, ARM_FEATURE_V4T)
40f0984d40SFabiano Rosas #define ENABLE_ARCH_5     arm_dc_feature(s, ARM_FEATURE_V5)
41f0984d40SFabiano Rosas /* currently all emulated v5 cores are also v5TE, so don't bother */
42f0984d40SFabiano Rosas #define ENABLE_ARCH_5TE   arm_dc_feature(s, ARM_FEATURE_V5)
43f0984d40SFabiano Rosas #define ENABLE_ARCH_5J    dc_isar_feature(aa32_jazelle, s)
44f0984d40SFabiano Rosas #define ENABLE_ARCH_6     arm_dc_feature(s, ARM_FEATURE_V6)
45f0984d40SFabiano Rosas #define ENABLE_ARCH_6K    arm_dc_feature(s, ARM_FEATURE_V6K)
46f0984d40SFabiano Rosas #define ENABLE_ARCH_6T2   arm_dc_feature(s, ARM_FEATURE_THUMB2)
47f0984d40SFabiano Rosas #define ENABLE_ARCH_7     arm_dc_feature(s, ARM_FEATURE_V7)
48f0984d40SFabiano Rosas #define ENABLE_ARCH_8     arm_dc_feature(s, ARM_FEATURE_V8)
49f0984d40SFabiano Rosas 
50f0984d40SFabiano Rosas #include "translate.h"
51f0984d40SFabiano Rosas #include "translate-a32.h"
52f0984d40SFabiano Rosas 
53f0984d40SFabiano Rosas /* These are TCG temporaries used only by the legacy iwMMXt decoder */
54f0984d40SFabiano Rosas static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
55f0984d40SFabiano Rosas /* These are TCG globals which alias CPUARMState fields */
56f0984d40SFabiano Rosas static TCGv_i32 cpu_R[16];
57f0984d40SFabiano Rosas TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF;
58f0984d40SFabiano Rosas TCGv_i64 cpu_exclusive_addr;
59f0984d40SFabiano Rosas TCGv_i64 cpu_exclusive_val;
60f0984d40SFabiano Rosas 
61f0984d40SFabiano Rosas #include "exec/gen-icount.h"
62f0984d40SFabiano Rosas 
63f0984d40SFabiano Rosas static const char * const regnames[] =
64f0984d40SFabiano Rosas     { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
65f0984d40SFabiano Rosas       "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" };
66f0984d40SFabiano Rosas 
67f0984d40SFabiano Rosas 
68f0984d40SFabiano Rosas /* initialize TCG globals.  */
69f0984d40SFabiano Rosas void arm_translate_init(void)
70f0984d40SFabiano Rosas {
71f0984d40SFabiano Rosas     int i;
72f0984d40SFabiano Rosas 
73f0984d40SFabiano Rosas     for (i = 0; i < 16; i++) {
74f0984d40SFabiano Rosas         cpu_R[i] = tcg_global_mem_new_i32(cpu_env,
75f0984d40SFabiano Rosas                                           offsetof(CPUARMState, regs[i]),
76f0984d40SFabiano Rosas                                           regnames[i]);
77f0984d40SFabiano Rosas     }
78f0984d40SFabiano Rosas     cpu_CF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, CF), "CF");
79f0984d40SFabiano Rosas     cpu_NF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, NF), "NF");
80f0984d40SFabiano Rosas     cpu_VF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, VF), "VF");
81f0984d40SFabiano Rosas     cpu_ZF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, ZF), "ZF");
82f0984d40SFabiano Rosas 
83f0984d40SFabiano Rosas     cpu_exclusive_addr = tcg_global_mem_new_i64(cpu_env,
84f0984d40SFabiano Rosas         offsetof(CPUARMState, exclusive_addr), "exclusive_addr");
85f0984d40SFabiano Rosas     cpu_exclusive_val = tcg_global_mem_new_i64(cpu_env,
86f0984d40SFabiano Rosas         offsetof(CPUARMState, exclusive_val), "exclusive_val");
87f0984d40SFabiano Rosas 
88f0984d40SFabiano Rosas     a64_translate_init();
89f0984d40SFabiano Rosas }
90f0984d40SFabiano Rosas 
91f0984d40SFabiano Rosas uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
92f0984d40SFabiano Rosas {
93f0984d40SFabiano Rosas     /* Expand the encoded constant as per AdvSIMDExpandImm pseudocode */
94f0984d40SFabiano Rosas     switch (cmode) {
95f0984d40SFabiano Rosas     case 0: case 1:
96f0984d40SFabiano Rosas         /* no-op */
97f0984d40SFabiano Rosas         break;
98f0984d40SFabiano Rosas     case 2: case 3:
99f0984d40SFabiano Rosas         imm <<= 8;
100f0984d40SFabiano Rosas         break;
101f0984d40SFabiano Rosas     case 4: case 5:
102f0984d40SFabiano Rosas         imm <<= 16;
103f0984d40SFabiano Rosas         break;
104f0984d40SFabiano Rosas     case 6: case 7:
105f0984d40SFabiano Rosas         imm <<= 24;
106f0984d40SFabiano Rosas         break;
107f0984d40SFabiano Rosas     case 8: case 9:
108f0984d40SFabiano Rosas         imm |= imm << 16;
109f0984d40SFabiano Rosas         break;
110f0984d40SFabiano Rosas     case 10: case 11:
111f0984d40SFabiano Rosas         imm = (imm << 8) | (imm << 24);
112f0984d40SFabiano Rosas         break;
113f0984d40SFabiano Rosas     case 12:
114f0984d40SFabiano Rosas         imm = (imm << 8) | 0xff;
115f0984d40SFabiano Rosas         break;
116f0984d40SFabiano Rosas     case 13:
117f0984d40SFabiano Rosas         imm = (imm << 16) | 0xffff;
118f0984d40SFabiano Rosas         break;
119f0984d40SFabiano Rosas     case 14:
120f0984d40SFabiano Rosas         if (op) {
121f0984d40SFabiano Rosas             /*
122f0984d40SFabiano Rosas              * This and cmode == 15 op == 1 are the only cases where
123f0984d40SFabiano Rosas              * the top and bottom 32 bits of the encoded constant differ.
124f0984d40SFabiano Rosas              */
125f0984d40SFabiano Rosas             uint64_t imm64 = 0;
126f0984d40SFabiano Rosas             int n;
127f0984d40SFabiano Rosas 
128f0984d40SFabiano Rosas             for (n = 0; n < 8; n++) {
129f0984d40SFabiano Rosas                 if (imm & (1 << n)) {
130f0984d40SFabiano Rosas                     imm64 |= (0xffULL << (n * 8));
131f0984d40SFabiano Rosas                 }
132f0984d40SFabiano Rosas             }
133f0984d40SFabiano Rosas             return imm64;
134f0984d40SFabiano Rosas         }
135f0984d40SFabiano Rosas         imm |= (imm << 8) | (imm << 16) | (imm << 24);
136f0984d40SFabiano Rosas         break;
137f0984d40SFabiano Rosas     case 15:
138f0984d40SFabiano Rosas         if (op) {
139f0984d40SFabiano Rosas             /* Reserved encoding for AArch32; valid for AArch64 */
140f0984d40SFabiano Rosas             uint64_t imm64 = (uint64_t)(imm & 0x3f) << 48;
141f0984d40SFabiano Rosas             if (imm & 0x80) {
142f0984d40SFabiano Rosas                 imm64 |= 0x8000000000000000ULL;
143f0984d40SFabiano Rosas             }
144f0984d40SFabiano Rosas             if (imm & 0x40) {
145f0984d40SFabiano Rosas                 imm64 |= 0x3fc0000000000000ULL;
146f0984d40SFabiano Rosas             } else {
147f0984d40SFabiano Rosas                 imm64 |= 0x4000000000000000ULL;
148f0984d40SFabiano Rosas             }
149f0984d40SFabiano Rosas             return imm64;
150f0984d40SFabiano Rosas         }
151f0984d40SFabiano Rosas         imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
152f0984d40SFabiano Rosas             | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
153f0984d40SFabiano Rosas         break;
154f0984d40SFabiano Rosas     }
155f0984d40SFabiano Rosas     if (op) {
156f0984d40SFabiano Rosas         imm = ~imm;
157f0984d40SFabiano Rosas     }
158f0984d40SFabiano Rosas     return dup_const(MO_32, imm);
159f0984d40SFabiano Rosas }
160f0984d40SFabiano Rosas 
161f0984d40SFabiano Rosas /* Generate a label used for skipping this instruction */
162f0984d40SFabiano Rosas void arm_gen_condlabel(DisasContext *s)
163f0984d40SFabiano Rosas {
164f0984d40SFabiano Rosas     if (!s->condjmp) {
165f0984d40SFabiano Rosas         s->condlabel = gen_disas_label(s);
166f0984d40SFabiano Rosas         s->condjmp = 1;
167f0984d40SFabiano Rosas     }
168f0984d40SFabiano Rosas }
169f0984d40SFabiano Rosas 
170f0984d40SFabiano Rosas /* Flags for the disas_set_da_iss info argument:
171f0984d40SFabiano Rosas  * lower bits hold the Rt register number, higher bits are flags.
172f0984d40SFabiano Rosas  */
173f0984d40SFabiano Rosas typedef enum ISSInfo {
174f0984d40SFabiano Rosas     ISSNone = 0,
175f0984d40SFabiano Rosas     ISSRegMask = 0x1f,
176f0984d40SFabiano Rosas     ISSInvalid = (1 << 5),
177f0984d40SFabiano Rosas     ISSIsAcqRel = (1 << 6),
178f0984d40SFabiano Rosas     ISSIsWrite = (1 << 7),
179f0984d40SFabiano Rosas     ISSIs16Bit = (1 << 8),
180f0984d40SFabiano Rosas } ISSInfo;
181f0984d40SFabiano Rosas 
182f0984d40SFabiano Rosas /*
183f0984d40SFabiano Rosas  * Store var into env + offset to a member with size bytes.
184f0984d40SFabiano Rosas  * Free var after use.
185f0984d40SFabiano Rosas  */
186f0984d40SFabiano Rosas void store_cpu_offset(TCGv_i32 var, int offset, int size)
187f0984d40SFabiano Rosas {
188f0984d40SFabiano Rosas     switch (size) {
189f0984d40SFabiano Rosas     case 1:
190f0984d40SFabiano Rosas         tcg_gen_st8_i32(var, cpu_env, offset);
191f0984d40SFabiano Rosas         break;
192f0984d40SFabiano Rosas     case 4:
193f0984d40SFabiano Rosas         tcg_gen_st_i32(var, cpu_env, offset);
194f0984d40SFabiano Rosas         break;
195f0984d40SFabiano Rosas     default:
196f0984d40SFabiano Rosas         g_assert_not_reached();
197f0984d40SFabiano Rosas     }
198f0984d40SFabiano Rosas     tcg_temp_free_i32(var);
199f0984d40SFabiano Rosas }
200f0984d40SFabiano Rosas 
201f0984d40SFabiano Rosas /* Save the syndrome information for a Data Abort */
202f0984d40SFabiano Rosas static void disas_set_da_iss(DisasContext *s, MemOp memop, ISSInfo issinfo)
203f0984d40SFabiano Rosas {
204f0984d40SFabiano Rosas     uint32_t syn;
205f0984d40SFabiano Rosas     int sas = memop & MO_SIZE;
206f0984d40SFabiano Rosas     bool sse = memop & MO_SIGN;
207f0984d40SFabiano Rosas     bool is_acqrel = issinfo & ISSIsAcqRel;
208f0984d40SFabiano Rosas     bool is_write = issinfo & ISSIsWrite;
209f0984d40SFabiano Rosas     bool is_16bit = issinfo & ISSIs16Bit;
210f0984d40SFabiano Rosas     int srt = issinfo & ISSRegMask;
211f0984d40SFabiano Rosas 
212f0984d40SFabiano Rosas     if (issinfo & ISSInvalid) {
213f0984d40SFabiano Rosas         /* Some callsites want to conditionally provide ISS info,
214f0984d40SFabiano Rosas          * eg "only if this was not a writeback"
215f0984d40SFabiano Rosas          */
216f0984d40SFabiano Rosas         return;
217f0984d40SFabiano Rosas     }
218f0984d40SFabiano Rosas 
219f0984d40SFabiano Rosas     if (srt == 15) {
220f0984d40SFabiano Rosas         /* For AArch32, insns where the src/dest is R15 never generate
221f0984d40SFabiano Rosas          * ISS information. Catching that here saves checking at all
222f0984d40SFabiano Rosas          * the call sites.
223f0984d40SFabiano Rosas          */
224f0984d40SFabiano Rosas         return;
225f0984d40SFabiano Rosas     }
226f0984d40SFabiano Rosas 
227f0984d40SFabiano Rosas     syn = syn_data_abort_with_iss(0, sas, sse, srt, 0, is_acqrel,
228f0984d40SFabiano Rosas                                   0, 0, 0, is_write, 0, is_16bit);
229f0984d40SFabiano Rosas     disas_set_insn_syndrome(s, syn);
230f0984d40SFabiano Rosas }
231f0984d40SFabiano Rosas 
232f0984d40SFabiano Rosas static inline int get_a32_user_mem_index(DisasContext *s)
233f0984d40SFabiano Rosas {
234f0984d40SFabiano Rosas     /* Return the core mmu_idx to use for A32/T32 "unprivileged load/store"
235f0984d40SFabiano Rosas      * insns:
236f0984d40SFabiano Rosas      *  if PL2, UNPREDICTABLE (we choose to implement as if PL0)
237f0984d40SFabiano Rosas      *  otherwise, access as if at PL0.
238f0984d40SFabiano Rosas      */
239f0984d40SFabiano Rosas     switch (s->mmu_idx) {
240f0984d40SFabiano Rosas     case ARMMMUIdx_E3:
241f0984d40SFabiano Rosas     case ARMMMUIdx_E2:        /* this one is UNPREDICTABLE */
242f0984d40SFabiano Rosas     case ARMMMUIdx_E10_0:
243f0984d40SFabiano Rosas     case ARMMMUIdx_E10_1:
244f0984d40SFabiano Rosas     case ARMMMUIdx_E10_1_PAN:
245f0984d40SFabiano Rosas         return arm_to_core_mmu_idx(ARMMMUIdx_E10_0);
246f0984d40SFabiano Rosas     case ARMMMUIdx_MUser:
247f0984d40SFabiano Rosas     case ARMMMUIdx_MPriv:
248f0984d40SFabiano Rosas         return arm_to_core_mmu_idx(ARMMMUIdx_MUser);
249f0984d40SFabiano Rosas     case ARMMMUIdx_MUserNegPri:
250f0984d40SFabiano Rosas     case ARMMMUIdx_MPrivNegPri:
251f0984d40SFabiano Rosas         return arm_to_core_mmu_idx(ARMMMUIdx_MUserNegPri);
252f0984d40SFabiano Rosas     case ARMMMUIdx_MSUser:
253f0984d40SFabiano Rosas     case ARMMMUIdx_MSPriv:
254f0984d40SFabiano Rosas         return arm_to_core_mmu_idx(ARMMMUIdx_MSUser);
255f0984d40SFabiano Rosas     case ARMMMUIdx_MSUserNegPri:
256f0984d40SFabiano Rosas     case ARMMMUIdx_MSPrivNegPri:
257f0984d40SFabiano Rosas         return arm_to_core_mmu_idx(ARMMMUIdx_MSUserNegPri);
258f0984d40SFabiano Rosas     default:
259f0984d40SFabiano Rosas         g_assert_not_reached();
260f0984d40SFabiano Rosas     }
261f0984d40SFabiano Rosas }
262f0984d40SFabiano Rosas 
263f0984d40SFabiano Rosas /* The pc_curr difference for an architectural jump. */
264f0984d40SFabiano Rosas static target_long jmp_diff(DisasContext *s, target_long diff)
265f0984d40SFabiano Rosas {
266f0984d40SFabiano Rosas     return diff + (s->thumb ? 4 : 8);
267f0984d40SFabiano Rosas }
268f0984d40SFabiano Rosas 
269f0984d40SFabiano Rosas static void gen_pc_plus_diff(DisasContext *s, TCGv_i32 var, target_long diff)
270f0984d40SFabiano Rosas {
271f0984d40SFabiano Rosas     assert(s->pc_save != -1);
27203a648c4SAnton Johansson     if (tb_cflags(s->base.tb) & CF_PCREL) {
273f0984d40SFabiano Rosas         tcg_gen_addi_i32(var, cpu_R[15], (s->pc_curr - s->pc_save) + diff);
274f0984d40SFabiano Rosas     } else {
275f0984d40SFabiano Rosas         tcg_gen_movi_i32(var, s->pc_curr + diff);
276f0984d40SFabiano Rosas     }
277f0984d40SFabiano Rosas }
278f0984d40SFabiano Rosas 
279f0984d40SFabiano Rosas /* Set a variable to the value of a CPU register.  */
280f0984d40SFabiano Rosas void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
281f0984d40SFabiano Rosas {
282f0984d40SFabiano Rosas     if (reg == 15) {
283f0984d40SFabiano Rosas         gen_pc_plus_diff(s, var, jmp_diff(s, 0));
284f0984d40SFabiano Rosas     } else {
285f0984d40SFabiano Rosas         tcg_gen_mov_i32(var, cpu_R[reg]);
286f0984d40SFabiano Rosas     }
287f0984d40SFabiano Rosas }
288f0984d40SFabiano Rosas 
289f0984d40SFabiano Rosas /*
290f0984d40SFabiano Rosas  * Create a new temp, REG + OFS, except PC is ALIGN(PC, 4).
291f0984d40SFabiano Rosas  * This is used for load/store for which use of PC implies (literal),
292f0984d40SFabiano Rosas  * or ADD that implies ADR.
293f0984d40SFabiano Rosas  */
294f0984d40SFabiano Rosas TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
295f0984d40SFabiano Rosas {
296f0984d40SFabiano Rosas     TCGv_i32 tmp = tcg_temp_new_i32();
297f0984d40SFabiano Rosas 
298f0984d40SFabiano Rosas     if (reg == 15) {
299f0984d40SFabiano Rosas         /*
300f0984d40SFabiano Rosas          * This address is computed from an aligned PC:
301f0984d40SFabiano Rosas          * subtract off the low bits.
302f0984d40SFabiano Rosas          */
303f0984d40SFabiano Rosas         gen_pc_plus_diff(s, tmp, jmp_diff(s, ofs - (s->pc_curr & 3)));
304f0984d40SFabiano Rosas     } else {
305f0984d40SFabiano Rosas         tcg_gen_addi_i32(tmp, cpu_R[reg], ofs);
306f0984d40SFabiano Rosas     }
307f0984d40SFabiano Rosas     return tmp;
308f0984d40SFabiano Rosas }
309f0984d40SFabiano Rosas 
310f0984d40SFabiano Rosas /* Set a CPU register.  The source must be a temporary and will be
311f0984d40SFabiano Rosas    marked as dead.  */
312f0984d40SFabiano Rosas void store_reg(DisasContext *s, int reg, TCGv_i32 var)
313f0984d40SFabiano Rosas {
314f0984d40SFabiano Rosas     if (reg == 15) {
315f0984d40SFabiano Rosas         /* In Thumb mode, we must ignore bit 0.
316f0984d40SFabiano Rosas          * In ARM mode, for ARMv4 and ARMv5, it is UNPREDICTABLE if bits [1:0]
317f0984d40SFabiano Rosas          * are not 0b00, but for ARMv6 and above, we must ignore bits [1:0].
318f0984d40SFabiano Rosas          * We choose to ignore [1:0] in ARM mode for all architecture versions.
319f0984d40SFabiano Rosas          */
320f0984d40SFabiano Rosas         tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
321f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_JUMP;
322f0984d40SFabiano Rosas         s->pc_save = -1;
323f0984d40SFabiano Rosas     } else if (reg == 13 && arm_dc_feature(s, ARM_FEATURE_M)) {
324f0984d40SFabiano Rosas         /* For M-profile SP bits [1:0] are always zero */
325f0984d40SFabiano Rosas         tcg_gen_andi_i32(var, var, ~3);
326f0984d40SFabiano Rosas     }
327f0984d40SFabiano Rosas     tcg_gen_mov_i32(cpu_R[reg], var);
328f0984d40SFabiano Rosas     tcg_temp_free_i32(var);
329f0984d40SFabiano Rosas }
330f0984d40SFabiano Rosas 
331f0984d40SFabiano Rosas /*
332f0984d40SFabiano Rosas  * Variant of store_reg which applies v8M stack-limit checks before updating
333f0984d40SFabiano Rosas  * SP. If the check fails this will result in an exception being taken.
334f0984d40SFabiano Rosas  * We disable the stack checks for CONFIG_USER_ONLY because we have
335f0984d40SFabiano Rosas  * no idea what the stack limits should be in that case.
336f0984d40SFabiano Rosas  * If stack checking is not being done this just acts like store_reg().
337f0984d40SFabiano Rosas  */
338f0984d40SFabiano Rosas static void store_sp_checked(DisasContext *s, TCGv_i32 var)
339f0984d40SFabiano Rosas {
340f0984d40SFabiano Rosas #ifndef CONFIG_USER_ONLY
341f0984d40SFabiano Rosas     if (s->v8m_stackcheck) {
342f0984d40SFabiano Rosas         gen_helper_v8m_stackcheck(cpu_env, var);
343f0984d40SFabiano Rosas     }
344f0984d40SFabiano Rosas #endif
345f0984d40SFabiano Rosas     store_reg(s, 13, var);
346f0984d40SFabiano Rosas }
347f0984d40SFabiano Rosas 
348f0984d40SFabiano Rosas /* Value extensions.  */
349f0984d40SFabiano Rosas #define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
350f0984d40SFabiano Rosas #define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
351f0984d40SFabiano Rosas #define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
352f0984d40SFabiano Rosas #define gen_sxth(var) tcg_gen_ext16s_i32(var, var)
353f0984d40SFabiano Rosas 
354f0984d40SFabiano Rosas #define gen_sxtb16(var) gen_helper_sxtb16(var, var)
355f0984d40SFabiano Rosas #define gen_uxtb16(var) gen_helper_uxtb16(var, var)
356f0984d40SFabiano Rosas 
357f0984d40SFabiano Rosas void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
358f0984d40SFabiano Rosas {
359f0984d40SFabiano Rosas     gen_helper_cpsr_write(cpu_env, var, tcg_constant_i32(mask));
360f0984d40SFabiano Rosas }
361f0984d40SFabiano Rosas 
362f0984d40SFabiano Rosas static void gen_rebuild_hflags(DisasContext *s, bool new_el)
363f0984d40SFabiano Rosas {
364f0984d40SFabiano Rosas     bool m_profile = arm_dc_feature(s, ARM_FEATURE_M);
365f0984d40SFabiano Rosas 
366f0984d40SFabiano Rosas     if (new_el) {
367f0984d40SFabiano Rosas         if (m_profile) {
368f0984d40SFabiano Rosas             gen_helper_rebuild_hflags_m32_newel(cpu_env);
369f0984d40SFabiano Rosas         } else {
370f0984d40SFabiano Rosas             gen_helper_rebuild_hflags_a32_newel(cpu_env);
371f0984d40SFabiano Rosas         }
372f0984d40SFabiano Rosas     } else {
373f0984d40SFabiano Rosas         TCGv_i32 tcg_el = tcg_constant_i32(s->current_el);
374f0984d40SFabiano Rosas         if (m_profile) {
375f0984d40SFabiano Rosas             gen_helper_rebuild_hflags_m32(cpu_env, tcg_el);
376f0984d40SFabiano Rosas         } else {
377f0984d40SFabiano Rosas             gen_helper_rebuild_hflags_a32(cpu_env, tcg_el);
378f0984d40SFabiano Rosas         }
379f0984d40SFabiano Rosas     }
380f0984d40SFabiano Rosas }
381f0984d40SFabiano Rosas 
382f0984d40SFabiano Rosas static void gen_exception_internal(int excp)
383f0984d40SFabiano Rosas {
384f0984d40SFabiano Rosas     assert(excp_is_internal(excp));
385f0984d40SFabiano Rosas     gen_helper_exception_internal(cpu_env, tcg_constant_i32(excp));
386f0984d40SFabiano Rosas }
387f0984d40SFabiano Rosas 
388f0984d40SFabiano Rosas static void gen_singlestep_exception(DisasContext *s)
389f0984d40SFabiano Rosas {
390f0984d40SFabiano Rosas     /* We just completed step of an insn. Move from Active-not-pending
391f0984d40SFabiano Rosas      * to Active-pending, and then also take the swstep exception.
392f0984d40SFabiano Rosas      * This corresponds to making the (IMPDEF) choice to prioritize
393f0984d40SFabiano Rosas      * swstep exceptions over asynchronous exceptions taken to an exception
394f0984d40SFabiano Rosas      * level where debug is disabled. This choice has the advantage that
395f0984d40SFabiano Rosas      * we do not need to maintain internal state corresponding to the
396f0984d40SFabiano Rosas      * ISV/EX syndrome bits between completion of the step and generation
397f0984d40SFabiano Rosas      * of the exception, and our syndrome information is always correct.
398f0984d40SFabiano Rosas      */
399f0984d40SFabiano Rosas     gen_ss_advance(s);
400f0984d40SFabiano Rosas     gen_swstep_exception(s, 1, s->is_ldex);
401f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_NORETURN;
402f0984d40SFabiano Rosas }
403f0984d40SFabiano Rosas 
404f0984d40SFabiano Rosas void clear_eci_state(DisasContext *s)
405f0984d40SFabiano Rosas {
406f0984d40SFabiano Rosas     /*
407f0984d40SFabiano Rosas      * Clear any ECI/ICI state: used when a load multiple/store
408f0984d40SFabiano Rosas      * multiple insn executes.
409f0984d40SFabiano Rosas      */
410f0984d40SFabiano Rosas     if (s->eci) {
411f0984d40SFabiano Rosas         store_cpu_field_constant(0, condexec_bits);
412f0984d40SFabiano Rosas         s->eci = 0;
413f0984d40SFabiano Rosas     }
414f0984d40SFabiano Rosas }
415f0984d40SFabiano Rosas 
416f0984d40SFabiano Rosas static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
417f0984d40SFabiano Rosas {
418f0984d40SFabiano Rosas     TCGv_i32 tmp1 = tcg_temp_new_i32();
419f0984d40SFabiano Rosas     TCGv_i32 tmp2 = tcg_temp_new_i32();
420f0984d40SFabiano Rosas     tcg_gen_ext16s_i32(tmp1, a);
421f0984d40SFabiano Rosas     tcg_gen_ext16s_i32(tmp2, b);
422f0984d40SFabiano Rosas     tcg_gen_mul_i32(tmp1, tmp1, tmp2);
423f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp2);
424f0984d40SFabiano Rosas     tcg_gen_sari_i32(a, a, 16);
425f0984d40SFabiano Rosas     tcg_gen_sari_i32(b, b, 16);
426f0984d40SFabiano Rosas     tcg_gen_mul_i32(b, b, a);
427f0984d40SFabiano Rosas     tcg_gen_mov_i32(a, tmp1);
428f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp1);
429f0984d40SFabiano Rosas }
430f0984d40SFabiano Rosas 
431f0984d40SFabiano Rosas /* Byteswap each halfword.  */
432f0984d40SFabiano Rosas void gen_rev16(TCGv_i32 dest, TCGv_i32 var)
433f0984d40SFabiano Rosas {
434f0984d40SFabiano Rosas     TCGv_i32 tmp = tcg_temp_new_i32();
435f0984d40SFabiano Rosas     TCGv_i32 mask = tcg_constant_i32(0x00ff00ff);
436f0984d40SFabiano Rosas     tcg_gen_shri_i32(tmp, var, 8);
437f0984d40SFabiano Rosas     tcg_gen_and_i32(tmp, tmp, mask);
438f0984d40SFabiano Rosas     tcg_gen_and_i32(var, var, mask);
439f0984d40SFabiano Rosas     tcg_gen_shli_i32(var, var, 8);
440f0984d40SFabiano Rosas     tcg_gen_or_i32(dest, var, tmp);
441f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
442f0984d40SFabiano Rosas }
443f0984d40SFabiano Rosas 
444f0984d40SFabiano Rosas /* Byteswap low halfword and sign extend.  */
445f0984d40SFabiano Rosas static void gen_revsh(TCGv_i32 dest, TCGv_i32 var)
446f0984d40SFabiano Rosas {
447f0984d40SFabiano Rosas     tcg_gen_bswap16_i32(var, var, TCG_BSWAP_OS);
448f0984d40SFabiano Rosas }
449f0984d40SFabiano Rosas 
450f0984d40SFabiano Rosas /* Dual 16-bit add.  Result placed in t0 and t1 is marked as dead.
451f0984d40SFabiano Rosas     tmp = (t0 ^ t1) & 0x8000;
452f0984d40SFabiano Rosas     t0 &= ~0x8000;
453f0984d40SFabiano Rosas     t1 &= ~0x8000;
454f0984d40SFabiano Rosas     t0 = (t0 + t1) ^ tmp;
455f0984d40SFabiano Rosas  */
456f0984d40SFabiano Rosas 
457f0984d40SFabiano Rosas static void gen_add16(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
458f0984d40SFabiano Rosas {
459f0984d40SFabiano Rosas     TCGv_i32 tmp = tcg_temp_new_i32();
460f0984d40SFabiano Rosas     tcg_gen_xor_i32(tmp, t0, t1);
461f0984d40SFabiano Rosas     tcg_gen_andi_i32(tmp, tmp, 0x8000);
462f0984d40SFabiano Rosas     tcg_gen_andi_i32(t0, t0, ~0x8000);
463f0984d40SFabiano Rosas     tcg_gen_andi_i32(t1, t1, ~0x8000);
464f0984d40SFabiano Rosas     tcg_gen_add_i32(t0, t0, t1);
465f0984d40SFabiano Rosas     tcg_gen_xor_i32(dest, t0, tmp);
466f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
467f0984d40SFabiano Rosas }
468f0984d40SFabiano Rosas 
469f0984d40SFabiano Rosas /* Set N and Z flags from var.  */
470f0984d40SFabiano Rosas static inline void gen_logic_CC(TCGv_i32 var)
471f0984d40SFabiano Rosas {
472f0984d40SFabiano Rosas     tcg_gen_mov_i32(cpu_NF, var);
473f0984d40SFabiano Rosas     tcg_gen_mov_i32(cpu_ZF, var);
474f0984d40SFabiano Rosas }
475f0984d40SFabiano Rosas 
476f0984d40SFabiano Rosas /* dest = T0 + T1 + CF. */
477f0984d40SFabiano Rosas static void gen_add_carry(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
478f0984d40SFabiano Rosas {
479f0984d40SFabiano Rosas     tcg_gen_add_i32(dest, t0, t1);
480f0984d40SFabiano Rosas     tcg_gen_add_i32(dest, dest, cpu_CF);
481f0984d40SFabiano Rosas }
482f0984d40SFabiano Rosas 
483f0984d40SFabiano Rosas /* dest = T0 - T1 + CF - 1.  */
484f0984d40SFabiano Rosas static void gen_sub_carry(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
485f0984d40SFabiano Rosas {
486f0984d40SFabiano Rosas     tcg_gen_sub_i32(dest, t0, t1);
487f0984d40SFabiano Rosas     tcg_gen_add_i32(dest, dest, cpu_CF);
488f0984d40SFabiano Rosas     tcg_gen_subi_i32(dest, dest, 1);
489f0984d40SFabiano Rosas }
490f0984d40SFabiano Rosas 
491f0984d40SFabiano Rosas /* dest = T0 + T1. Compute C, N, V and Z flags */
492f0984d40SFabiano Rosas static void gen_add_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
493f0984d40SFabiano Rosas {
494f0984d40SFabiano Rosas     TCGv_i32 tmp = tcg_temp_new_i32();
495f0984d40SFabiano Rosas     tcg_gen_movi_i32(tmp, 0);
496f0984d40SFabiano Rosas     tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, t1, tmp);
497f0984d40SFabiano Rosas     tcg_gen_mov_i32(cpu_ZF, cpu_NF);
498f0984d40SFabiano Rosas     tcg_gen_xor_i32(cpu_VF, cpu_NF, t0);
499f0984d40SFabiano Rosas     tcg_gen_xor_i32(tmp, t0, t1);
500f0984d40SFabiano Rosas     tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
501f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
502f0984d40SFabiano Rosas     tcg_gen_mov_i32(dest, cpu_NF);
503f0984d40SFabiano Rosas }
504f0984d40SFabiano Rosas 
505f0984d40SFabiano Rosas /* dest = T0 + T1 + CF.  Compute C, N, V and Z flags */
506f0984d40SFabiano Rosas static void gen_adc_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
507f0984d40SFabiano Rosas {
508f0984d40SFabiano Rosas     TCGv_i32 tmp = tcg_temp_new_i32();
509f0984d40SFabiano Rosas     if (TCG_TARGET_HAS_add2_i32) {
510f0984d40SFabiano Rosas         tcg_gen_movi_i32(tmp, 0);
511f0984d40SFabiano Rosas         tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp);
512f0984d40SFabiano Rosas         tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp);
513f0984d40SFabiano Rosas     } else {
514f0984d40SFabiano Rosas         TCGv_i64 q0 = tcg_temp_new_i64();
515f0984d40SFabiano Rosas         TCGv_i64 q1 = tcg_temp_new_i64();
516f0984d40SFabiano Rosas         tcg_gen_extu_i32_i64(q0, t0);
517f0984d40SFabiano Rosas         tcg_gen_extu_i32_i64(q1, t1);
518f0984d40SFabiano Rosas         tcg_gen_add_i64(q0, q0, q1);
519f0984d40SFabiano Rosas         tcg_gen_extu_i32_i64(q1, cpu_CF);
520f0984d40SFabiano Rosas         tcg_gen_add_i64(q0, q0, q1);
521f0984d40SFabiano Rosas         tcg_gen_extr_i64_i32(cpu_NF, cpu_CF, q0);
522f0984d40SFabiano Rosas         tcg_temp_free_i64(q0);
523f0984d40SFabiano Rosas         tcg_temp_free_i64(q1);
524f0984d40SFabiano Rosas     }
525f0984d40SFabiano Rosas     tcg_gen_mov_i32(cpu_ZF, cpu_NF);
526f0984d40SFabiano Rosas     tcg_gen_xor_i32(cpu_VF, cpu_NF, t0);
527f0984d40SFabiano Rosas     tcg_gen_xor_i32(tmp, t0, t1);
528f0984d40SFabiano Rosas     tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
529f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
530f0984d40SFabiano Rosas     tcg_gen_mov_i32(dest, cpu_NF);
531f0984d40SFabiano Rosas }
532f0984d40SFabiano Rosas 
533f0984d40SFabiano Rosas /* dest = T0 - T1. Compute C, N, V and Z flags */
534f0984d40SFabiano Rosas static void gen_sub_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
535f0984d40SFabiano Rosas {
536f0984d40SFabiano Rosas     TCGv_i32 tmp;
537f0984d40SFabiano Rosas     tcg_gen_sub_i32(cpu_NF, t0, t1);
538f0984d40SFabiano Rosas     tcg_gen_mov_i32(cpu_ZF, cpu_NF);
539f0984d40SFabiano Rosas     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0, t1);
540f0984d40SFabiano Rosas     tcg_gen_xor_i32(cpu_VF, cpu_NF, t0);
541f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
542f0984d40SFabiano Rosas     tcg_gen_xor_i32(tmp, t0, t1);
543f0984d40SFabiano Rosas     tcg_gen_and_i32(cpu_VF, cpu_VF, tmp);
544f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
545f0984d40SFabiano Rosas     tcg_gen_mov_i32(dest, cpu_NF);
546f0984d40SFabiano Rosas }
547f0984d40SFabiano Rosas 
548f0984d40SFabiano Rosas /* dest = T0 + ~T1 + CF.  Compute C, N, V and Z flags */
549f0984d40SFabiano Rosas static void gen_sbc_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
550f0984d40SFabiano Rosas {
551f0984d40SFabiano Rosas     TCGv_i32 tmp = tcg_temp_new_i32();
552f0984d40SFabiano Rosas     tcg_gen_not_i32(tmp, t1);
553f0984d40SFabiano Rosas     gen_adc_CC(dest, t0, tmp);
554f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
555f0984d40SFabiano Rosas }
556f0984d40SFabiano Rosas 
557f0984d40SFabiano Rosas #define GEN_SHIFT(name)                                               \
558f0984d40SFabiano Rosas static void gen_##name(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)       \
559f0984d40SFabiano Rosas {                                                                     \
560f0984d40SFabiano Rosas     TCGv_i32 tmpd = tcg_temp_new_i32();                               \
561f0984d40SFabiano Rosas     TCGv_i32 tmp1 = tcg_temp_new_i32();                               \
562f0984d40SFabiano Rosas     TCGv_i32 zero = tcg_constant_i32(0);                              \
563f0984d40SFabiano Rosas     tcg_gen_andi_i32(tmp1, t1, 0x1f);                                 \
564f0984d40SFabiano Rosas     tcg_gen_##name##_i32(tmpd, t0, tmp1);                             \
565f0984d40SFabiano Rosas     tcg_gen_andi_i32(tmp1, t1, 0xe0);                                 \
566f0984d40SFabiano Rosas     tcg_gen_movcond_i32(TCG_COND_NE, dest, tmp1, zero, zero, tmpd);   \
567f0984d40SFabiano Rosas     tcg_temp_free_i32(tmpd);                                          \
568f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp1);                                          \
569f0984d40SFabiano Rosas }
570f0984d40SFabiano Rosas GEN_SHIFT(shl)
571f0984d40SFabiano Rosas GEN_SHIFT(shr)
572f0984d40SFabiano Rosas #undef GEN_SHIFT
573f0984d40SFabiano Rosas 
574f0984d40SFabiano Rosas static void gen_sar(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
575f0984d40SFabiano Rosas {
576f0984d40SFabiano Rosas     TCGv_i32 tmp1 = tcg_temp_new_i32();
577f0984d40SFabiano Rosas 
578f0984d40SFabiano Rosas     tcg_gen_andi_i32(tmp1, t1, 0xff);
579f0984d40SFabiano Rosas     tcg_gen_umin_i32(tmp1, tmp1, tcg_constant_i32(31));
580f0984d40SFabiano Rosas     tcg_gen_sar_i32(dest, t0, tmp1);
581f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp1);
582f0984d40SFabiano Rosas }
583f0984d40SFabiano Rosas 
584f0984d40SFabiano Rosas static void shifter_out_im(TCGv_i32 var, int shift)
585f0984d40SFabiano Rosas {
586f0984d40SFabiano Rosas     tcg_gen_extract_i32(cpu_CF, var, shift, 1);
587f0984d40SFabiano Rosas }
588f0984d40SFabiano Rosas 
589f0984d40SFabiano Rosas /* Shift by immediate.  Includes special handling for shift == 0.  */
590f0984d40SFabiano Rosas static inline void gen_arm_shift_im(TCGv_i32 var, int shiftop,
591f0984d40SFabiano Rosas                                     int shift, int flags)
592f0984d40SFabiano Rosas {
593f0984d40SFabiano Rosas     switch (shiftop) {
594f0984d40SFabiano Rosas     case 0: /* LSL */
595f0984d40SFabiano Rosas         if (shift != 0) {
596f0984d40SFabiano Rosas             if (flags)
597f0984d40SFabiano Rosas                 shifter_out_im(var, 32 - shift);
598f0984d40SFabiano Rosas             tcg_gen_shli_i32(var, var, shift);
599f0984d40SFabiano Rosas         }
600f0984d40SFabiano Rosas         break;
601f0984d40SFabiano Rosas     case 1: /* LSR */
602f0984d40SFabiano Rosas         if (shift == 0) {
603f0984d40SFabiano Rosas             if (flags) {
604f0984d40SFabiano Rosas                 tcg_gen_shri_i32(cpu_CF, var, 31);
605f0984d40SFabiano Rosas             }
606f0984d40SFabiano Rosas             tcg_gen_movi_i32(var, 0);
607f0984d40SFabiano Rosas         } else {
608f0984d40SFabiano Rosas             if (flags)
609f0984d40SFabiano Rosas                 shifter_out_im(var, shift - 1);
610f0984d40SFabiano Rosas             tcg_gen_shri_i32(var, var, shift);
611f0984d40SFabiano Rosas         }
612f0984d40SFabiano Rosas         break;
613f0984d40SFabiano Rosas     case 2: /* ASR */
614f0984d40SFabiano Rosas         if (shift == 0)
615f0984d40SFabiano Rosas             shift = 32;
616f0984d40SFabiano Rosas         if (flags)
617f0984d40SFabiano Rosas             shifter_out_im(var, shift - 1);
618f0984d40SFabiano Rosas         if (shift == 32)
619f0984d40SFabiano Rosas           shift = 31;
620f0984d40SFabiano Rosas         tcg_gen_sari_i32(var, var, shift);
621f0984d40SFabiano Rosas         break;
622f0984d40SFabiano Rosas     case 3: /* ROR/RRX */
623f0984d40SFabiano Rosas         if (shift != 0) {
624f0984d40SFabiano Rosas             if (flags)
625f0984d40SFabiano Rosas                 shifter_out_im(var, shift - 1);
626f0984d40SFabiano Rosas             tcg_gen_rotri_i32(var, var, shift); break;
627f0984d40SFabiano Rosas         } else {
628f0984d40SFabiano Rosas             TCGv_i32 tmp = tcg_temp_new_i32();
629f0984d40SFabiano Rosas             tcg_gen_shli_i32(tmp, cpu_CF, 31);
630f0984d40SFabiano Rosas             if (flags)
631f0984d40SFabiano Rosas                 shifter_out_im(var, 0);
632f0984d40SFabiano Rosas             tcg_gen_shri_i32(var, var, 1);
633f0984d40SFabiano Rosas             tcg_gen_or_i32(var, var, tmp);
634f0984d40SFabiano Rosas             tcg_temp_free_i32(tmp);
635f0984d40SFabiano Rosas         }
636f0984d40SFabiano Rosas     }
637f0984d40SFabiano Rosas };
638f0984d40SFabiano Rosas 
639f0984d40SFabiano Rosas static inline void gen_arm_shift_reg(TCGv_i32 var, int shiftop,
640f0984d40SFabiano Rosas                                      TCGv_i32 shift, int flags)
641f0984d40SFabiano Rosas {
642f0984d40SFabiano Rosas     if (flags) {
643f0984d40SFabiano Rosas         switch (shiftop) {
644f0984d40SFabiano Rosas         case 0: gen_helper_shl_cc(var, cpu_env, var, shift); break;
645f0984d40SFabiano Rosas         case 1: gen_helper_shr_cc(var, cpu_env, var, shift); break;
646f0984d40SFabiano Rosas         case 2: gen_helper_sar_cc(var, cpu_env, var, shift); break;
647f0984d40SFabiano Rosas         case 3: gen_helper_ror_cc(var, cpu_env, var, shift); break;
648f0984d40SFabiano Rosas         }
649f0984d40SFabiano Rosas     } else {
650f0984d40SFabiano Rosas         switch (shiftop) {
651f0984d40SFabiano Rosas         case 0:
652f0984d40SFabiano Rosas             gen_shl(var, var, shift);
653f0984d40SFabiano Rosas             break;
654f0984d40SFabiano Rosas         case 1:
655f0984d40SFabiano Rosas             gen_shr(var, var, shift);
656f0984d40SFabiano Rosas             break;
657f0984d40SFabiano Rosas         case 2:
658f0984d40SFabiano Rosas             gen_sar(var, var, shift);
659f0984d40SFabiano Rosas             break;
660f0984d40SFabiano Rosas         case 3: tcg_gen_andi_i32(shift, shift, 0x1f);
661f0984d40SFabiano Rosas                 tcg_gen_rotr_i32(var, var, shift); break;
662f0984d40SFabiano Rosas         }
663f0984d40SFabiano Rosas     }
664f0984d40SFabiano Rosas     tcg_temp_free_i32(shift);
665f0984d40SFabiano Rosas }
666f0984d40SFabiano Rosas 
667f0984d40SFabiano Rosas /*
668f0984d40SFabiano Rosas  * Generate a conditional based on ARM condition code cc.
669f0984d40SFabiano Rosas  * This is common between ARM and Aarch64 targets.
670f0984d40SFabiano Rosas  */
671f0984d40SFabiano Rosas void arm_test_cc(DisasCompare *cmp, int cc)
672f0984d40SFabiano Rosas {
673f0984d40SFabiano Rosas     TCGv_i32 value;
674f0984d40SFabiano Rosas     TCGCond cond;
675f0984d40SFabiano Rosas     bool global = true;
676f0984d40SFabiano Rosas 
677f0984d40SFabiano Rosas     switch (cc) {
678f0984d40SFabiano Rosas     case 0: /* eq: Z */
679f0984d40SFabiano Rosas     case 1: /* ne: !Z */
680f0984d40SFabiano Rosas         cond = TCG_COND_EQ;
681f0984d40SFabiano Rosas         value = cpu_ZF;
682f0984d40SFabiano Rosas         break;
683f0984d40SFabiano Rosas 
684f0984d40SFabiano Rosas     case 2: /* cs: C */
685f0984d40SFabiano Rosas     case 3: /* cc: !C */
686f0984d40SFabiano Rosas         cond = TCG_COND_NE;
687f0984d40SFabiano Rosas         value = cpu_CF;
688f0984d40SFabiano Rosas         break;
689f0984d40SFabiano Rosas 
690f0984d40SFabiano Rosas     case 4: /* mi: N */
691f0984d40SFabiano Rosas     case 5: /* pl: !N */
692f0984d40SFabiano Rosas         cond = TCG_COND_LT;
693f0984d40SFabiano Rosas         value = cpu_NF;
694f0984d40SFabiano Rosas         break;
695f0984d40SFabiano Rosas 
696f0984d40SFabiano Rosas     case 6: /* vs: V */
697f0984d40SFabiano Rosas     case 7: /* vc: !V */
698f0984d40SFabiano Rosas         cond = TCG_COND_LT;
699f0984d40SFabiano Rosas         value = cpu_VF;
700f0984d40SFabiano Rosas         break;
701f0984d40SFabiano Rosas 
702f0984d40SFabiano Rosas     case 8: /* hi: C && !Z */
703f0984d40SFabiano Rosas     case 9: /* ls: !C || Z -> !(C && !Z) */
704f0984d40SFabiano Rosas         cond = TCG_COND_NE;
705f0984d40SFabiano Rosas         value = tcg_temp_new_i32();
706f0984d40SFabiano Rosas         global = false;
707f0984d40SFabiano Rosas         /* CF is 1 for C, so -CF is an all-bits-set mask for C;
708f0984d40SFabiano Rosas            ZF is non-zero for !Z; so AND the two subexpressions.  */
709f0984d40SFabiano Rosas         tcg_gen_neg_i32(value, cpu_CF);
710f0984d40SFabiano Rosas         tcg_gen_and_i32(value, value, cpu_ZF);
711f0984d40SFabiano Rosas         break;
712f0984d40SFabiano Rosas 
713f0984d40SFabiano Rosas     case 10: /* ge: N == V -> N ^ V == 0 */
714f0984d40SFabiano Rosas     case 11: /* lt: N != V -> N ^ V != 0 */
715f0984d40SFabiano Rosas         /* Since we're only interested in the sign bit, == 0 is >= 0.  */
716f0984d40SFabiano Rosas         cond = TCG_COND_GE;
717f0984d40SFabiano Rosas         value = tcg_temp_new_i32();
718f0984d40SFabiano Rosas         global = false;
719f0984d40SFabiano Rosas         tcg_gen_xor_i32(value, cpu_VF, cpu_NF);
720f0984d40SFabiano Rosas         break;
721f0984d40SFabiano Rosas 
722f0984d40SFabiano Rosas     case 12: /* gt: !Z && N == V */
723f0984d40SFabiano Rosas     case 13: /* le: Z || N != V */
724f0984d40SFabiano Rosas         cond = TCG_COND_NE;
725f0984d40SFabiano Rosas         value = tcg_temp_new_i32();
726f0984d40SFabiano Rosas         global = false;
727f0984d40SFabiano Rosas         /* (N == V) is equal to the sign bit of ~(NF ^ VF).  Propagate
728f0984d40SFabiano Rosas          * the sign bit then AND with ZF to yield the result.  */
729f0984d40SFabiano Rosas         tcg_gen_xor_i32(value, cpu_VF, cpu_NF);
730f0984d40SFabiano Rosas         tcg_gen_sari_i32(value, value, 31);
731f0984d40SFabiano Rosas         tcg_gen_andc_i32(value, cpu_ZF, value);
732f0984d40SFabiano Rosas         break;
733f0984d40SFabiano Rosas 
734f0984d40SFabiano Rosas     case 14: /* always */
735f0984d40SFabiano Rosas     case 15: /* always */
736f0984d40SFabiano Rosas         /* Use the ALWAYS condition, which will fold early.
737f0984d40SFabiano Rosas          * It doesn't matter what we use for the value.  */
738f0984d40SFabiano Rosas         cond = TCG_COND_ALWAYS;
739f0984d40SFabiano Rosas         value = cpu_ZF;
740f0984d40SFabiano Rosas         goto no_invert;
741f0984d40SFabiano Rosas 
742f0984d40SFabiano Rosas     default:
743f0984d40SFabiano Rosas         fprintf(stderr, "Bad condition code 0x%x\n", cc);
744f0984d40SFabiano Rosas         abort();
745f0984d40SFabiano Rosas     }
746f0984d40SFabiano Rosas 
747f0984d40SFabiano Rosas     if (cc & 1) {
748f0984d40SFabiano Rosas         cond = tcg_invert_cond(cond);
749f0984d40SFabiano Rosas     }
750f0984d40SFabiano Rosas 
751f0984d40SFabiano Rosas  no_invert:
752f0984d40SFabiano Rosas     cmp->cond = cond;
753f0984d40SFabiano Rosas     cmp->value = value;
754f0984d40SFabiano Rosas     cmp->value_global = global;
755f0984d40SFabiano Rosas }
756f0984d40SFabiano Rosas 
757f0984d40SFabiano Rosas void arm_free_cc(DisasCompare *cmp)
758f0984d40SFabiano Rosas {
759f0984d40SFabiano Rosas     if (!cmp->value_global) {
760f0984d40SFabiano Rosas         tcg_temp_free_i32(cmp->value);
761f0984d40SFabiano Rosas     }
762f0984d40SFabiano Rosas }
763f0984d40SFabiano Rosas 
764f0984d40SFabiano Rosas void arm_jump_cc(DisasCompare *cmp, TCGLabel *label)
765f0984d40SFabiano Rosas {
766f0984d40SFabiano Rosas     tcg_gen_brcondi_i32(cmp->cond, cmp->value, 0, label);
767f0984d40SFabiano Rosas }
768f0984d40SFabiano Rosas 
769f0984d40SFabiano Rosas void arm_gen_test_cc(int cc, TCGLabel *label)
770f0984d40SFabiano Rosas {
771f0984d40SFabiano Rosas     DisasCompare cmp;
772f0984d40SFabiano Rosas     arm_test_cc(&cmp, cc);
773f0984d40SFabiano Rosas     arm_jump_cc(&cmp, label);
774f0984d40SFabiano Rosas     arm_free_cc(&cmp);
775f0984d40SFabiano Rosas }
776f0984d40SFabiano Rosas 
777f0984d40SFabiano Rosas void gen_set_condexec(DisasContext *s)
778f0984d40SFabiano Rosas {
779f0984d40SFabiano Rosas     if (s->condexec_mask) {
780f0984d40SFabiano Rosas         uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
781f0984d40SFabiano Rosas 
782f0984d40SFabiano Rosas         store_cpu_field_constant(val, condexec_bits);
783f0984d40SFabiano Rosas     }
784f0984d40SFabiano Rosas }
785f0984d40SFabiano Rosas 
786f0984d40SFabiano Rosas void gen_update_pc(DisasContext *s, target_long diff)
787f0984d40SFabiano Rosas {
788f0984d40SFabiano Rosas     gen_pc_plus_diff(s, cpu_R[15], diff);
789f0984d40SFabiano Rosas     s->pc_save = s->pc_curr + diff;
790f0984d40SFabiano Rosas }
791f0984d40SFabiano Rosas 
792f0984d40SFabiano Rosas /* Set PC and Thumb state from var.  var is marked as dead.  */
793f0984d40SFabiano Rosas static inline void gen_bx(DisasContext *s, TCGv_i32 var)
794f0984d40SFabiano Rosas {
795f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_JUMP;
796f0984d40SFabiano Rosas     tcg_gen_andi_i32(cpu_R[15], var, ~1);
797f0984d40SFabiano Rosas     tcg_gen_andi_i32(var, var, 1);
798f0984d40SFabiano Rosas     store_cpu_field(var, thumb);
799f0984d40SFabiano Rosas     s->pc_save = -1;
800f0984d40SFabiano Rosas }
801f0984d40SFabiano Rosas 
802f0984d40SFabiano Rosas /*
803f0984d40SFabiano Rosas  * Set PC and Thumb state from var. var is marked as dead.
804f0984d40SFabiano Rosas  * For M-profile CPUs, include logic to detect exception-return
805f0984d40SFabiano Rosas  * branches and handle them. This is needed for Thumb POP/LDM to PC, LDR to PC,
806f0984d40SFabiano Rosas  * and BX reg, and no others, and happens only for code in Handler mode.
807f0984d40SFabiano Rosas  * The Security Extension also requires us to check for the FNC_RETURN
808f0984d40SFabiano Rosas  * which signals a function return from non-secure state; this can happen
809f0984d40SFabiano Rosas  * in both Handler and Thread mode.
810f0984d40SFabiano Rosas  * To avoid having to do multiple comparisons in inline generated code,
811f0984d40SFabiano Rosas  * we make the check we do here loose, so it will match for EXC_RETURN
812f0984d40SFabiano Rosas  * in Thread mode. For system emulation do_v7m_exception_exit() checks
813f0984d40SFabiano Rosas  * for these spurious cases and returns without doing anything (giving
814f0984d40SFabiano Rosas  * the same behaviour as for a branch to a non-magic address).
815f0984d40SFabiano Rosas  *
816f0984d40SFabiano Rosas  * In linux-user mode it is unclear what the right behaviour for an
817f0984d40SFabiano Rosas  * attempted FNC_RETURN should be, because in real hardware this will go
818f0984d40SFabiano Rosas  * directly to Secure code (ie not the Linux kernel) which will then treat
819f0984d40SFabiano Rosas  * the error in any way it chooses. For QEMU we opt to make the FNC_RETURN
820f0984d40SFabiano Rosas  * attempt behave the way it would on a CPU without the security extension,
821f0984d40SFabiano Rosas  * which is to say "like a normal branch". That means we can simply treat
822f0984d40SFabiano Rosas  * all branches as normal with no magic address behaviour.
823f0984d40SFabiano Rosas  */
824f0984d40SFabiano Rosas static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
825f0984d40SFabiano Rosas {
826f0984d40SFabiano Rosas     /* Generate the same code here as for a simple bx, but flag via
827f0984d40SFabiano Rosas      * s->base.is_jmp that we need to do the rest of the work later.
828f0984d40SFabiano Rosas      */
829f0984d40SFabiano Rosas     gen_bx(s, var);
830f0984d40SFabiano Rosas #ifndef CONFIG_USER_ONLY
831f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY) ||
832f0984d40SFabiano Rosas         (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M))) {
833f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_BX_EXCRET;
834f0984d40SFabiano Rosas     }
835f0984d40SFabiano Rosas #endif
836f0984d40SFabiano Rosas }
837f0984d40SFabiano Rosas 
838f0984d40SFabiano Rosas static inline void gen_bx_excret_final_code(DisasContext *s)
839f0984d40SFabiano Rosas {
840f0984d40SFabiano Rosas     /* Generate the code to finish possible exception return and end the TB */
841f0984d40SFabiano Rosas     DisasLabel excret_label = gen_disas_label(s);
842f0984d40SFabiano Rosas     uint32_t min_magic;
843f0984d40SFabiano Rosas 
844f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY)) {
845f0984d40SFabiano Rosas         /* Covers FNC_RETURN and EXC_RETURN magic */
846f0984d40SFabiano Rosas         min_magic = FNC_RETURN_MIN_MAGIC;
847f0984d40SFabiano Rosas     } else {
848f0984d40SFabiano Rosas         /* EXC_RETURN magic only */
849f0984d40SFabiano Rosas         min_magic = EXC_RETURN_MIN_MAGIC;
850f0984d40SFabiano Rosas     }
851f0984d40SFabiano Rosas 
852f0984d40SFabiano Rosas     /* Is the new PC value in the magic range indicating exception return? */
853f0984d40SFabiano Rosas     tcg_gen_brcondi_i32(TCG_COND_GEU, cpu_R[15], min_magic, excret_label.label);
854f0984d40SFabiano Rosas     /* No: end the TB as we would for a DISAS_JMP */
855f0984d40SFabiano Rosas     if (s->ss_active) {
856f0984d40SFabiano Rosas         gen_singlestep_exception(s);
857f0984d40SFabiano Rosas     } else {
858f0984d40SFabiano Rosas         tcg_gen_exit_tb(NULL, 0);
859f0984d40SFabiano Rosas     }
860f0984d40SFabiano Rosas     set_disas_label(s, excret_label);
861f0984d40SFabiano Rosas     /* Yes: this is an exception return.
862f0984d40SFabiano Rosas      * At this point in runtime env->regs[15] and env->thumb will hold
863f0984d40SFabiano Rosas      * the exception-return magic number, which do_v7m_exception_exit()
864f0984d40SFabiano Rosas      * will read. Nothing else will be able to see those values because
865f0984d40SFabiano Rosas      * the cpu-exec main loop guarantees that we will always go straight
866f0984d40SFabiano Rosas      * from raising the exception to the exception-handling code.
867f0984d40SFabiano Rosas      *
868f0984d40SFabiano Rosas      * gen_ss_advance(s) does nothing on M profile currently but
869f0984d40SFabiano Rosas      * calling it is conceptually the right thing as we have executed
870f0984d40SFabiano Rosas      * this instruction (compare SWI, HVC, SMC handling).
871f0984d40SFabiano Rosas      */
872f0984d40SFabiano Rosas     gen_ss_advance(s);
873f0984d40SFabiano Rosas     gen_exception_internal(EXCP_EXCEPTION_EXIT);
874f0984d40SFabiano Rosas }
875f0984d40SFabiano Rosas 
876f0984d40SFabiano Rosas static inline void gen_bxns(DisasContext *s, int rm)
877f0984d40SFabiano Rosas {
878f0984d40SFabiano Rosas     TCGv_i32 var = load_reg(s, rm);
879f0984d40SFabiano Rosas 
880f0984d40SFabiano Rosas     /* The bxns helper may raise an EXCEPTION_EXIT exception, so in theory
881f0984d40SFabiano Rosas      * we need to sync state before calling it, but:
882f0984d40SFabiano Rosas      *  - we don't need to do gen_update_pc() because the bxns helper will
883f0984d40SFabiano Rosas      *    always set the PC itself
884f0984d40SFabiano Rosas      *  - we don't need to do gen_set_condexec() because BXNS is UNPREDICTABLE
885f0984d40SFabiano Rosas      *    unless it's outside an IT block or the last insn in an IT block,
886f0984d40SFabiano Rosas      *    so we know that condexec == 0 (already set at the top of the TB)
887f0984d40SFabiano Rosas      *    is correct in the non-UNPREDICTABLE cases, and we can choose
888f0984d40SFabiano Rosas      *    "zeroes the IT bits" as our UNPREDICTABLE behaviour otherwise.
889f0984d40SFabiano Rosas      */
890f0984d40SFabiano Rosas     gen_helper_v7m_bxns(cpu_env, var);
891f0984d40SFabiano Rosas     tcg_temp_free_i32(var);
892f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_EXIT;
893f0984d40SFabiano Rosas }
894f0984d40SFabiano Rosas 
895f0984d40SFabiano Rosas static inline void gen_blxns(DisasContext *s, int rm)
896f0984d40SFabiano Rosas {
897f0984d40SFabiano Rosas     TCGv_i32 var = load_reg(s, rm);
898f0984d40SFabiano Rosas 
899f0984d40SFabiano Rosas     /* We don't need to sync condexec state, for the same reason as bxns.
900f0984d40SFabiano Rosas      * We do however need to set the PC, because the blxns helper reads it.
901f0984d40SFabiano Rosas      * The blxns helper may throw an exception.
902f0984d40SFabiano Rosas      */
903f0984d40SFabiano Rosas     gen_update_pc(s, curr_insn_len(s));
904f0984d40SFabiano Rosas     gen_helper_v7m_blxns(cpu_env, var);
905f0984d40SFabiano Rosas     tcg_temp_free_i32(var);
906f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_EXIT;
907f0984d40SFabiano Rosas }
908f0984d40SFabiano Rosas 
909f0984d40SFabiano Rosas /* Variant of store_reg which uses branch&exchange logic when storing
910f0984d40SFabiano Rosas    to r15 in ARM architecture v7 and above. The source must be a temporary
911f0984d40SFabiano Rosas    and will be marked as dead. */
912f0984d40SFabiano Rosas static inline void store_reg_bx(DisasContext *s, int reg, TCGv_i32 var)
913f0984d40SFabiano Rosas {
914f0984d40SFabiano Rosas     if (reg == 15 && ENABLE_ARCH_7) {
915f0984d40SFabiano Rosas         gen_bx(s, var);
916f0984d40SFabiano Rosas     } else {
917f0984d40SFabiano Rosas         store_reg(s, reg, var);
918f0984d40SFabiano Rosas     }
919f0984d40SFabiano Rosas }
920f0984d40SFabiano Rosas 
921f0984d40SFabiano Rosas /* Variant of store_reg which uses branch&exchange logic when storing
922f0984d40SFabiano Rosas  * to r15 in ARM architecture v5T and above. This is used for storing
923f0984d40SFabiano Rosas  * the results of a LDR/LDM/POP into r15, and corresponds to the cases
924f0984d40SFabiano Rosas  * in the ARM ARM which use the LoadWritePC() pseudocode function. */
925f0984d40SFabiano Rosas static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var)
926f0984d40SFabiano Rosas {
927f0984d40SFabiano Rosas     if (reg == 15 && ENABLE_ARCH_5) {
928f0984d40SFabiano Rosas         gen_bx_excret(s, var);
929f0984d40SFabiano Rosas     } else {
930f0984d40SFabiano Rosas         store_reg(s, reg, var);
931f0984d40SFabiano Rosas     }
932f0984d40SFabiano Rosas }
933f0984d40SFabiano Rosas 
934f0984d40SFabiano Rosas #ifdef CONFIG_USER_ONLY
935f0984d40SFabiano Rosas #define IS_USER_ONLY 1
936f0984d40SFabiano Rosas #else
937f0984d40SFabiano Rosas #define IS_USER_ONLY 0
938f0984d40SFabiano Rosas #endif
939f0984d40SFabiano Rosas 
940f0984d40SFabiano Rosas MemOp pow2_align(unsigned i)
941f0984d40SFabiano Rosas {
942f0984d40SFabiano Rosas     static const MemOp mop_align[] = {
943f0984d40SFabiano Rosas         0, MO_ALIGN_2, MO_ALIGN_4, MO_ALIGN_8, MO_ALIGN_16,
944f0984d40SFabiano Rosas         /*
945f0984d40SFabiano Rosas          * FIXME: TARGET_PAGE_BITS_MIN affects TLB_FLAGS_MASK such
946f0984d40SFabiano Rosas          * that 256-bit alignment (MO_ALIGN_32) cannot be supported:
947f0984d40SFabiano Rosas          * see get_alignment_bits(). Enforce only 128-bit alignment for now.
948f0984d40SFabiano Rosas          */
949f0984d40SFabiano Rosas         MO_ALIGN_16
950f0984d40SFabiano Rosas     };
951f0984d40SFabiano Rosas     g_assert(i < ARRAY_SIZE(mop_align));
952f0984d40SFabiano Rosas     return mop_align[i];
953f0984d40SFabiano Rosas }
954f0984d40SFabiano Rosas 
955f0984d40SFabiano Rosas /*
956f0984d40SFabiano Rosas  * Abstractions of "generate code to do a guest load/store for
957f0984d40SFabiano Rosas  * AArch32", where a vaddr is always 32 bits (and is zero
958f0984d40SFabiano Rosas  * extended if we're a 64 bit core) and  data is also
959f0984d40SFabiano Rosas  * 32 bits unless specifically doing a 64 bit access.
960f0984d40SFabiano Rosas  * These functions work like tcg_gen_qemu_{ld,st}* except
961f0984d40SFabiano Rosas  * that the address argument is TCGv_i32 rather than TCGv.
962f0984d40SFabiano Rosas  */
963f0984d40SFabiano Rosas 
964f0984d40SFabiano Rosas static TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op)
965f0984d40SFabiano Rosas {
966f0984d40SFabiano Rosas     TCGv addr = tcg_temp_new();
967f0984d40SFabiano Rosas     tcg_gen_extu_i32_tl(addr, a32);
968f0984d40SFabiano Rosas 
969f0984d40SFabiano Rosas     /* Not needed for user-mode BE32, where we use MO_BE instead.  */
970f0984d40SFabiano Rosas     if (!IS_USER_ONLY && s->sctlr_b && (op & MO_SIZE) < MO_32) {
971f0984d40SFabiano Rosas         tcg_gen_xori_tl(addr, addr, 4 - (1 << (op & MO_SIZE)));
972f0984d40SFabiano Rosas     }
973f0984d40SFabiano Rosas     return addr;
974f0984d40SFabiano Rosas }
975f0984d40SFabiano Rosas 
976f0984d40SFabiano Rosas /*
977f0984d40SFabiano Rosas  * Internal routines are used for NEON cases where the endianness
978f0984d40SFabiano Rosas  * and/or alignment has already been taken into account and manipulated.
979f0984d40SFabiano Rosas  */
980f0984d40SFabiano Rosas void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val,
981f0984d40SFabiano Rosas                               TCGv_i32 a32, int index, MemOp opc)
982f0984d40SFabiano Rosas {
983f0984d40SFabiano Rosas     TCGv addr = gen_aa32_addr(s, a32, opc);
984f0984d40SFabiano Rosas     tcg_gen_qemu_ld_i32(val, addr, index, opc);
985f0984d40SFabiano Rosas     tcg_temp_free(addr);
986f0984d40SFabiano Rosas }
987f0984d40SFabiano Rosas 
988f0984d40SFabiano Rosas void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val,
989f0984d40SFabiano Rosas                               TCGv_i32 a32, int index, MemOp opc)
990f0984d40SFabiano Rosas {
991f0984d40SFabiano Rosas     TCGv addr = gen_aa32_addr(s, a32, opc);
992f0984d40SFabiano Rosas     tcg_gen_qemu_st_i32(val, addr, index, opc);
993f0984d40SFabiano Rosas     tcg_temp_free(addr);
994f0984d40SFabiano Rosas }
995f0984d40SFabiano Rosas 
996f0984d40SFabiano Rosas void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val,
997f0984d40SFabiano Rosas                               TCGv_i32 a32, int index, MemOp opc)
998f0984d40SFabiano Rosas {
999f0984d40SFabiano Rosas     TCGv addr = gen_aa32_addr(s, a32, opc);
1000f0984d40SFabiano Rosas 
1001f0984d40SFabiano Rosas     tcg_gen_qemu_ld_i64(val, addr, index, opc);
1002f0984d40SFabiano Rosas 
1003f0984d40SFabiano Rosas     /* Not needed for user-mode BE32, where we use MO_BE instead.  */
1004f0984d40SFabiano Rosas     if (!IS_USER_ONLY && s->sctlr_b && (opc & MO_SIZE) == MO_64) {
1005f0984d40SFabiano Rosas         tcg_gen_rotri_i64(val, val, 32);
1006f0984d40SFabiano Rosas     }
1007f0984d40SFabiano Rosas     tcg_temp_free(addr);
1008f0984d40SFabiano Rosas }
1009f0984d40SFabiano Rosas 
1010f0984d40SFabiano Rosas void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val,
1011f0984d40SFabiano Rosas                               TCGv_i32 a32, int index, MemOp opc)
1012f0984d40SFabiano Rosas {
1013f0984d40SFabiano Rosas     TCGv addr = gen_aa32_addr(s, a32, opc);
1014f0984d40SFabiano Rosas 
1015f0984d40SFabiano Rosas     /* Not needed for user-mode BE32, where we use MO_BE instead.  */
1016f0984d40SFabiano Rosas     if (!IS_USER_ONLY && s->sctlr_b && (opc & MO_SIZE) == MO_64) {
1017f0984d40SFabiano Rosas         TCGv_i64 tmp = tcg_temp_new_i64();
1018f0984d40SFabiano Rosas         tcg_gen_rotri_i64(tmp, val, 32);
1019f0984d40SFabiano Rosas         tcg_gen_qemu_st_i64(tmp, addr, index, opc);
1020f0984d40SFabiano Rosas         tcg_temp_free_i64(tmp);
1021f0984d40SFabiano Rosas     } else {
1022f0984d40SFabiano Rosas         tcg_gen_qemu_st_i64(val, addr, index, opc);
1023f0984d40SFabiano Rosas     }
1024f0984d40SFabiano Rosas     tcg_temp_free(addr);
1025f0984d40SFabiano Rosas }
1026f0984d40SFabiano Rosas 
1027f0984d40SFabiano Rosas void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
1028f0984d40SFabiano Rosas                      int index, MemOp opc)
1029f0984d40SFabiano Rosas {
1030f0984d40SFabiano Rosas     gen_aa32_ld_internal_i32(s, val, a32, index, finalize_memop(s, opc));
1031f0984d40SFabiano Rosas }
1032f0984d40SFabiano Rosas 
1033f0984d40SFabiano Rosas void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
1034f0984d40SFabiano Rosas                      int index, MemOp opc)
1035f0984d40SFabiano Rosas {
1036f0984d40SFabiano Rosas     gen_aa32_st_internal_i32(s, val, a32, index, finalize_memop(s, opc));
1037f0984d40SFabiano Rosas }
1038f0984d40SFabiano Rosas 
1039f0984d40SFabiano Rosas void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
1040f0984d40SFabiano Rosas                      int index, MemOp opc)
1041f0984d40SFabiano Rosas {
1042f0984d40SFabiano Rosas     gen_aa32_ld_internal_i64(s, val, a32, index, finalize_memop(s, opc));
1043f0984d40SFabiano Rosas }
1044f0984d40SFabiano Rosas 
1045f0984d40SFabiano Rosas void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
1046f0984d40SFabiano Rosas                      int index, MemOp opc)
1047f0984d40SFabiano Rosas {
1048f0984d40SFabiano Rosas     gen_aa32_st_internal_i64(s, val, a32, index, finalize_memop(s, opc));
1049f0984d40SFabiano Rosas }
1050f0984d40SFabiano Rosas 
1051f0984d40SFabiano Rosas #define DO_GEN_LD(SUFF, OPC)                                            \
1052f0984d40SFabiano Rosas     static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \
1053f0984d40SFabiano Rosas                                          TCGv_i32 a32, int index)       \
1054f0984d40SFabiano Rosas     {                                                                   \
1055f0984d40SFabiano Rosas         gen_aa32_ld_i32(s, val, a32, index, OPC);                       \
1056f0984d40SFabiano Rosas     }
1057f0984d40SFabiano Rosas 
1058f0984d40SFabiano Rosas #define DO_GEN_ST(SUFF, OPC)                                            \
1059f0984d40SFabiano Rosas     static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \
1060f0984d40SFabiano Rosas                                          TCGv_i32 a32, int index)       \
1061f0984d40SFabiano Rosas     {                                                                   \
1062f0984d40SFabiano Rosas         gen_aa32_st_i32(s, val, a32, index, OPC);                       \
1063f0984d40SFabiano Rosas     }
1064f0984d40SFabiano Rosas 
1065f0984d40SFabiano Rosas static inline void gen_hvc(DisasContext *s, int imm16)
1066f0984d40SFabiano Rosas {
1067f0984d40SFabiano Rosas     /* The pre HVC helper handles cases when HVC gets trapped
1068f0984d40SFabiano Rosas      * as an undefined insn by runtime configuration (ie before
1069f0984d40SFabiano Rosas      * the insn really executes).
1070f0984d40SFabiano Rosas      */
1071f0984d40SFabiano Rosas     gen_update_pc(s, 0);
1072f0984d40SFabiano Rosas     gen_helper_pre_hvc(cpu_env);
1073f0984d40SFabiano Rosas     /* Otherwise we will treat this as a real exception which
1074f0984d40SFabiano Rosas      * happens after execution of the insn. (The distinction matters
1075f0984d40SFabiano Rosas      * for the PC value reported to the exception handler and also
1076f0984d40SFabiano Rosas      * for single stepping.)
1077f0984d40SFabiano Rosas      */
1078f0984d40SFabiano Rosas     s->svc_imm = imm16;
1079f0984d40SFabiano Rosas     gen_update_pc(s, curr_insn_len(s));
1080f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_HVC;
1081f0984d40SFabiano Rosas }
1082f0984d40SFabiano Rosas 
1083f0984d40SFabiano Rosas static inline void gen_smc(DisasContext *s)
1084f0984d40SFabiano Rosas {
1085f0984d40SFabiano Rosas     /* As with HVC, we may take an exception either before or after
1086f0984d40SFabiano Rosas      * the insn executes.
1087f0984d40SFabiano Rosas      */
1088f0984d40SFabiano Rosas     gen_update_pc(s, 0);
1089f0984d40SFabiano Rosas     gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa32_smc()));
1090f0984d40SFabiano Rosas     gen_update_pc(s, curr_insn_len(s));
1091f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_SMC;
1092f0984d40SFabiano Rosas }
1093f0984d40SFabiano Rosas 
1094f0984d40SFabiano Rosas static void gen_exception_internal_insn(DisasContext *s, int excp)
1095f0984d40SFabiano Rosas {
1096f0984d40SFabiano Rosas     gen_set_condexec(s);
1097f0984d40SFabiano Rosas     gen_update_pc(s, 0);
1098f0984d40SFabiano Rosas     gen_exception_internal(excp);
1099f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_NORETURN;
1100f0984d40SFabiano Rosas }
1101f0984d40SFabiano Rosas 
1102f0984d40SFabiano Rosas static void gen_exception_el_v(int excp, uint32_t syndrome, TCGv_i32 tcg_el)
1103f0984d40SFabiano Rosas {
1104f0984d40SFabiano Rosas     gen_helper_exception_with_syndrome_el(cpu_env, tcg_constant_i32(excp),
1105f0984d40SFabiano Rosas                                           tcg_constant_i32(syndrome), tcg_el);
1106f0984d40SFabiano Rosas }
1107f0984d40SFabiano Rosas 
1108f0984d40SFabiano Rosas static void gen_exception_el(int excp, uint32_t syndrome, uint32_t target_el)
1109f0984d40SFabiano Rosas {
1110f0984d40SFabiano Rosas     gen_exception_el_v(excp, syndrome, tcg_constant_i32(target_el));
1111f0984d40SFabiano Rosas }
1112f0984d40SFabiano Rosas 
1113f0984d40SFabiano Rosas static void gen_exception(int excp, uint32_t syndrome)
1114f0984d40SFabiano Rosas {
1115f0984d40SFabiano Rosas     gen_helper_exception_with_syndrome(cpu_env, tcg_constant_i32(excp),
1116f0984d40SFabiano Rosas                                        tcg_constant_i32(syndrome));
1117f0984d40SFabiano Rosas }
1118f0984d40SFabiano Rosas 
1119f0984d40SFabiano Rosas static void gen_exception_insn_el_v(DisasContext *s, target_long pc_diff,
1120f0984d40SFabiano Rosas                                     int excp, uint32_t syn, TCGv_i32 tcg_el)
1121f0984d40SFabiano Rosas {
1122f0984d40SFabiano Rosas     if (s->aarch64) {
1123f0984d40SFabiano Rosas         gen_a64_update_pc(s, pc_diff);
1124f0984d40SFabiano Rosas     } else {
1125f0984d40SFabiano Rosas         gen_set_condexec(s);
1126f0984d40SFabiano Rosas         gen_update_pc(s, pc_diff);
1127f0984d40SFabiano Rosas     }
1128f0984d40SFabiano Rosas     gen_exception_el_v(excp, syn, tcg_el);
1129f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_NORETURN;
1130f0984d40SFabiano Rosas }
1131f0984d40SFabiano Rosas 
1132f0984d40SFabiano Rosas void gen_exception_insn_el(DisasContext *s, target_long pc_diff, int excp,
1133f0984d40SFabiano Rosas                            uint32_t syn, uint32_t target_el)
1134f0984d40SFabiano Rosas {
1135f0984d40SFabiano Rosas     gen_exception_insn_el_v(s, pc_diff, excp, syn,
1136f0984d40SFabiano Rosas                             tcg_constant_i32(target_el));
1137f0984d40SFabiano Rosas }
1138f0984d40SFabiano Rosas 
1139f0984d40SFabiano Rosas void gen_exception_insn(DisasContext *s, target_long pc_diff,
1140f0984d40SFabiano Rosas                         int excp, uint32_t syn)
1141f0984d40SFabiano Rosas {
1142f0984d40SFabiano Rosas     if (s->aarch64) {
1143f0984d40SFabiano Rosas         gen_a64_update_pc(s, pc_diff);
1144f0984d40SFabiano Rosas     } else {
1145f0984d40SFabiano Rosas         gen_set_condexec(s);
1146f0984d40SFabiano Rosas         gen_update_pc(s, pc_diff);
1147f0984d40SFabiano Rosas     }
1148f0984d40SFabiano Rosas     gen_exception(excp, syn);
1149f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_NORETURN;
1150f0984d40SFabiano Rosas }
1151f0984d40SFabiano Rosas 
1152f0984d40SFabiano Rosas static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn)
1153f0984d40SFabiano Rosas {
1154f0984d40SFabiano Rosas     gen_set_condexec(s);
1155f0984d40SFabiano Rosas     gen_update_pc(s, 0);
1156f0984d40SFabiano Rosas     gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syn));
1157f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_NORETURN;
1158f0984d40SFabiano Rosas }
1159f0984d40SFabiano Rosas 
1160f0984d40SFabiano Rosas void unallocated_encoding(DisasContext *s)
1161f0984d40SFabiano Rosas {
1162f0984d40SFabiano Rosas     /* Unallocated and reserved encodings are uncategorized */
1163f0984d40SFabiano Rosas     gen_exception_insn(s, 0, EXCP_UDEF, syn_uncategorized());
1164f0984d40SFabiano Rosas }
1165f0984d40SFabiano Rosas 
1166f0984d40SFabiano Rosas /* Force a TB lookup after an instruction that changes the CPU state.  */
1167f0984d40SFabiano Rosas void gen_lookup_tb(DisasContext *s)
1168f0984d40SFabiano Rosas {
1169f0984d40SFabiano Rosas     gen_pc_plus_diff(s, cpu_R[15], curr_insn_len(s));
1170f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_EXIT;
1171f0984d40SFabiano Rosas }
1172f0984d40SFabiano Rosas 
1173f0984d40SFabiano Rosas static inline void gen_hlt(DisasContext *s, int imm)
1174f0984d40SFabiano Rosas {
1175f0984d40SFabiano Rosas     /* HLT. This has two purposes.
1176f0984d40SFabiano Rosas      * Architecturally, it is an external halting debug instruction.
1177f0984d40SFabiano Rosas      * Since QEMU doesn't implement external debug, we treat this as
1178f0984d40SFabiano Rosas      * it is required for halting debug disabled: it will UNDEF.
1179f0984d40SFabiano Rosas      * Secondly, "HLT 0x3C" is a T32 semihosting trap instruction,
1180f0984d40SFabiano Rosas      * and "HLT 0xF000" is an A32 semihosting syscall. These traps
1181f0984d40SFabiano Rosas      * must trigger semihosting even for ARMv7 and earlier, where
1182f0984d40SFabiano Rosas      * HLT was an undefined encoding.
1183f0984d40SFabiano Rosas      * In system mode, we don't allow userspace access to
1184f0984d40SFabiano Rosas      * semihosting, to provide some semblance of security
1185f0984d40SFabiano Rosas      * (and for consistency with our 32-bit semihosting).
1186f0984d40SFabiano Rosas      */
1187f0984d40SFabiano Rosas     if (semihosting_enabled(s->current_el == 0) &&
1188f0984d40SFabiano Rosas         (imm == (s->thumb ? 0x3c : 0xf000))) {
1189f0984d40SFabiano Rosas         gen_exception_internal_insn(s, EXCP_SEMIHOST);
1190f0984d40SFabiano Rosas         return;
1191f0984d40SFabiano Rosas     }
1192f0984d40SFabiano Rosas 
1193f0984d40SFabiano Rosas     unallocated_encoding(s);
1194f0984d40SFabiano Rosas }
1195f0984d40SFabiano Rosas 
1196f0984d40SFabiano Rosas /*
1197f0984d40SFabiano Rosas  * Return the offset of a "full" NEON Dreg.
1198f0984d40SFabiano Rosas  */
1199f0984d40SFabiano Rosas long neon_full_reg_offset(unsigned reg)
1200f0984d40SFabiano Rosas {
1201f0984d40SFabiano Rosas     return offsetof(CPUARMState, vfp.zregs[reg >> 1].d[reg & 1]);
1202f0984d40SFabiano Rosas }
1203f0984d40SFabiano Rosas 
1204f0984d40SFabiano Rosas /*
1205f0984d40SFabiano Rosas  * Return the offset of a 2**SIZE piece of a NEON register, at index ELE,
1206f0984d40SFabiano Rosas  * where 0 is the least significant end of the register.
1207f0984d40SFabiano Rosas  */
1208f0984d40SFabiano Rosas long neon_element_offset(int reg, int element, MemOp memop)
1209f0984d40SFabiano Rosas {
1210f0984d40SFabiano Rosas     int element_size = 1 << (memop & MO_SIZE);
1211f0984d40SFabiano Rosas     int ofs = element * element_size;
1212f0984d40SFabiano Rosas #if HOST_BIG_ENDIAN
1213f0984d40SFabiano Rosas     /*
1214f0984d40SFabiano Rosas      * Calculate the offset assuming fully little-endian,
1215f0984d40SFabiano Rosas      * then XOR to account for the order of the 8-byte units.
1216f0984d40SFabiano Rosas      */
1217f0984d40SFabiano Rosas     if (element_size < 8) {
1218f0984d40SFabiano Rosas         ofs ^= 8 - element_size;
1219f0984d40SFabiano Rosas     }
1220f0984d40SFabiano Rosas #endif
1221f0984d40SFabiano Rosas     return neon_full_reg_offset(reg) + ofs;
1222f0984d40SFabiano Rosas }
1223f0984d40SFabiano Rosas 
1224f0984d40SFabiano Rosas /* Return the offset of a VFP Dreg (dp = true) or VFP Sreg (dp = false). */
1225f0984d40SFabiano Rosas long vfp_reg_offset(bool dp, unsigned reg)
1226f0984d40SFabiano Rosas {
1227f0984d40SFabiano Rosas     if (dp) {
1228f0984d40SFabiano Rosas         return neon_element_offset(reg, 0, MO_64);
1229f0984d40SFabiano Rosas     } else {
1230f0984d40SFabiano Rosas         return neon_element_offset(reg >> 1, reg & 1, MO_32);
1231f0984d40SFabiano Rosas     }
1232f0984d40SFabiano Rosas }
1233f0984d40SFabiano Rosas 
1234f0984d40SFabiano Rosas void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop)
1235f0984d40SFabiano Rosas {
1236f0984d40SFabiano Rosas     long off = neon_element_offset(reg, ele, memop);
1237f0984d40SFabiano Rosas 
1238f0984d40SFabiano Rosas     switch (memop) {
1239f0984d40SFabiano Rosas     case MO_SB:
1240f0984d40SFabiano Rosas         tcg_gen_ld8s_i32(dest, cpu_env, off);
1241f0984d40SFabiano Rosas         break;
1242f0984d40SFabiano Rosas     case MO_UB:
1243f0984d40SFabiano Rosas         tcg_gen_ld8u_i32(dest, cpu_env, off);
1244f0984d40SFabiano Rosas         break;
1245f0984d40SFabiano Rosas     case MO_SW:
1246f0984d40SFabiano Rosas         tcg_gen_ld16s_i32(dest, cpu_env, off);
1247f0984d40SFabiano Rosas         break;
1248f0984d40SFabiano Rosas     case MO_UW:
1249f0984d40SFabiano Rosas         tcg_gen_ld16u_i32(dest, cpu_env, off);
1250f0984d40SFabiano Rosas         break;
1251f0984d40SFabiano Rosas     case MO_UL:
1252f0984d40SFabiano Rosas     case MO_SL:
1253f0984d40SFabiano Rosas         tcg_gen_ld_i32(dest, cpu_env, off);
1254f0984d40SFabiano Rosas         break;
1255f0984d40SFabiano Rosas     default:
1256f0984d40SFabiano Rosas         g_assert_not_reached();
1257f0984d40SFabiano Rosas     }
1258f0984d40SFabiano Rosas }
1259f0984d40SFabiano Rosas 
1260f0984d40SFabiano Rosas void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop)
1261f0984d40SFabiano Rosas {
1262f0984d40SFabiano Rosas     long off = neon_element_offset(reg, ele, memop);
1263f0984d40SFabiano Rosas 
1264f0984d40SFabiano Rosas     switch (memop) {
1265f0984d40SFabiano Rosas     case MO_SL:
1266f0984d40SFabiano Rosas         tcg_gen_ld32s_i64(dest, cpu_env, off);
1267f0984d40SFabiano Rosas         break;
1268f0984d40SFabiano Rosas     case MO_UL:
1269f0984d40SFabiano Rosas         tcg_gen_ld32u_i64(dest, cpu_env, off);
1270f0984d40SFabiano Rosas         break;
1271f0984d40SFabiano Rosas     case MO_UQ:
1272f0984d40SFabiano Rosas         tcg_gen_ld_i64(dest, cpu_env, off);
1273f0984d40SFabiano Rosas         break;
1274f0984d40SFabiano Rosas     default:
1275f0984d40SFabiano Rosas         g_assert_not_reached();
1276f0984d40SFabiano Rosas     }
1277f0984d40SFabiano Rosas }
1278f0984d40SFabiano Rosas 
1279f0984d40SFabiano Rosas void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop)
1280f0984d40SFabiano Rosas {
1281f0984d40SFabiano Rosas     long off = neon_element_offset(reg, ele, memop);
1282f0984d40SFabiano Rosas 
1283f0984d40SFabiano Rosas     switch (memop) {
1284f0984d40SFabiano Rosas     case MO_8:
1285f0984d40SFabiano Rosas         tcg_gen_st8_i32(src, cpu_env, off);
1286f0984d40SFabiano Rosas         break;
1287f0984d40SFabiano Rosas     case MO_16:
1288f0984d40SFabiano Rosas         tcg_gen_st16_i32(src, cpu_env, off);
1289f0984d40SFabiano Rosas         break;
1290f0984d40SFabiano Rosas     case MO_32:
1291f0984d40SFabiano Rosas         tcg_gen_st_i32(src, cpu_env, off);
1292f0984d40SFabiano Rosas         break;
1293f0984d40SFabiano Rosas     default:
1294f0984d40SFabiano Rosas         g_assert_not_reached();
1295f0984d40SFabiano Rosas     }
1296f0984d40SFabiano Rosas }
1297f0984d40SFabiano Rosas 
1298f0984d40SFabiano Rosas void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop)
1299f0984d40SFabiano Rosas {
1300f0984d40SFabiano Rosas     long off = neon_element_offset(reg, ele, memop);
1301f0984d40SFabiano Rosas 
1302f0984d40SFabiano Rosas     switch (memop) {
1303f0984d40SFabiano Rosas     case MO_32:
1304f0984d40SFabiano Rosas         tcg_gen_st32_i64(src, cpu_env, off);
1305f0984d40SFabiano Rosas         break;
1306f0984d40SFabiano Rosas     case MO_64:
1307f0984d40SFabiano Rosas         tcg_gen_st_i64(src, cpu_env, off);
1308f0984d40SFabiano Rosas         break;
1309f0984d40SFabiano Rosas     default:
1310f0984d40SFabiano Rosas         g_assert_not_reached();
1311f0984d40SFabiano Rosas     }
1312f0984d40SFabiano Rosas }
1313f0984d40SFabiano Rosas 
1314f0984d40SFabiano Rosas #define ARM_CP_RW_BIT   (1 << 20)
1315f0984d40SFabiano Rosas 
1316f0984d40SFabiano Rosas static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
1317f0984d40SFabiano Rosas {
1318f0984d40SFabiano Rosas     tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
1319f0984d40SFabiano Rosas }
1320f0984d40SFabiano Rosas 
1321f0984d40SFabiano Rosas static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
1322f0984d40SFabiano Rosas {
1323f0984d40SFabiano Rosas     tcg_gen_st_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
1324f0984d40SFabiano Rosas }
1325f0984d40SFabiano Rosas 
1326f0984d40SFabiano Rosas static inline TCGv_i32 iwmmxt_load_creg(int reg)
1327f0984d40SFabiano Rosas {
1328f0984d40SFabiano Rosas     TCGv_i32 var = tcg_temp_new_i32();
1329f0984d40SFabiano Rosas     tcg_gen_ld_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg]));
1330f0984d40SFabiano Rosas     return var;
1331f0984d40SFabiano Rosas }
1332f0984d40SFabiano Rosas 
1333f0984d40SFabiano Rosas static inline void iwmmxt_store_creg(int reg, TCGv_i32 var)
1334f0984d40SFabiano Rosas {
1335f0984d40SFabiano Rosas     tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg]));
1336f0984d40SFabiano Rosas     tcg_temp_free_i32(var);
1337f0984d40SFabiano Rosas }
1338f0984d40SFabiano Rosas 
1339f0984d40SFabiano Rosas static inline void gen_op_iwmmxt_movq_wRn_M0(int rn)
1340f0984d40SFabiano Rosas {
1341f0984d40SFabiano Rosas     iwmmxt_store_reg(cpu_M0, rn);
1342f0984d40SFabiano Rosas }
1343f0984d40SFabiano Rosas 
1344f0984d40SFabiano Rosas static inline void gen_op_iwmmxt_movq_M0_wRn(int rn)
1345f0984d40SFabiano Rosas {
1346f0984d40SFabiano Rosas     iwmmxt_load_reg(cpu_M0, rn);
1347f0984d40SFabiano Rosas }
1348f0984d40SFabiano Rosas 
1349f0984d40SFabiano Rosas static inline void gen_op_iwmmxt_orq_M0_wRn(int rn)
1350f0984d40SFabiano Rosas {
1351f0984d40SFabiano Rosas     iwmmxt_load_reg(cpu_V1, rn);
1352f0984d40SFabiano Rosas     tcg_gen_or_i64(cpu_M0, cpu_M0, cpu_V1);
1353f0984d40SFabiano Rosas }
1354f0984d40SFabiano Rosas 
1355f0984d40SFabiano Rosas static inline void gen_op_iwmmxt_andq_M0_wRn(int rn)
1356f0984d40SFabiano Rosas {
1357f0984d40SFabiano Rosas     iwmmxt_load_reg(cpu_V1, rn);
1358f0984d40SFabiano Rosas     tcg_gen_and_i64(cpu_M0, cpu_M0, cpu_V1);
1359f0984d40SFabiano Rosas }
1360f0984d40SFabiano Rosas 
1361f0984d40SFabiano Rosas static inline void gen_op_iwmmxt_xorq_M0_wRn(int rn)
1362f0984d40SFabiano Rosas {
1363f0984d40SFabiano Rosas     iwmmxt_load_reg(cpu_V1, rn);
1364f0984d40SFabiano Rosas     tcg_gen_xor_i64(cpu_M0, cpu_M0, cpu_V1);
1365f0984d40SFabiano Rosas }
1366f0984d40SFabiano Rosas 
1367f0984d40SFabiano Rosas #define IWMMXT_OP(name) \
1368f0984d40SFabiano Rosas static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
1369f0984d40SFabiano Rosas { \
1370f0984d40SFabiano Rosas     iwmmxt_load_reg(cpu_V1, rn); \
1371f0984d40SFabiano Rosas     gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \
1372f0984d40SFabiano Rosas }
1373f0984d40SFabiano Rosas 
1374f0984d40SFabiano Rosas #define IWMMXT_OP_ENV(name) \
1375f0984d40SFabiano Rosas static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
1376f0984d40SFabiano Rosas { \
1377f0984d40SFabiano Rosas     iwmmxt_load_reg(cpu_V1, rn); \
1378f0984d40SFabiano Rosas     gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \
1379f0984d40SFabiano Rosas }
1380f0984d40SFabiano Rosas 
1381f0984d40SFabiano Rosas #define IWMMXT_OP_ENV_SIZE(name) \
1382f0984d40SFabiano Rosas IWMMXT_OP_ENV(name##b) \
1383f0984d40SFabiano Rosas IWMMXT_OP_ENV(name##w) \
1384f0984d40SFabiano Rosas IWMMXT_OP_ENV(name##l)
1385f0984d40SFabiano Rosas 
1386f0984d40SFabiano Rosas #define IWMMXT_OP_ENV1(name) \
1387f0984d40SFabiano Rosas static inline void gen_op_iwmmxt_##name##_M0(void) \
1388f0984d40SFabiano Rosas { \
1389f0984d40SFabiano Rosas     gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \
1390f0984d40SFabiano Rosas }
1391f0984d40SFabiano Rosas 
1392f0984d40SFabiano Rosas IWMMXT_OP(maddsq)
1393f0984d40SFabiano Rosas IWMMXT_OP(madduq)
1394f0984d40SFabiano Rosas IWMMXT_OP(sadb)
1395f0984d40SFabiano Rosas IWMMXT_OP(sadw)
1396f0984d40SFabiano Rosas IWMMXT_OP(mulslw)
1397f0984d40SFabiano Rosas IWMMXT_OP(mulshw)
1398f0984d40SFabiano Rosas IWMMXT_OP(mululw)
1399f0984d40SFabiano Rosas IWMMXT_OP(muluhw)
1400f0984d40SFabiano Rosas IWMMXT_OP(macsw)
1401f0984d40SFabiano Rosas IWMMXT_OP(macuw)
1402f0984d40SFabiano Rosas 
1403f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(unpackl)
1404f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(unpackh)
1405f0984d40SFabiano Rosas 
1406f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpacklub)
1407f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpackluw)
1408f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpacklul)
1409f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpackhub)
1410f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpackhuw)
1411f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpackhul)
1412f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpacklsb)
1413f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpacklsw)
1414f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpacklsl)
1415f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpackhsb)
1416f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpackhsw)
1417f0984d40SFabiano Rosas IWMMXT_OP_ENV1(unpackhsl)
1418f0984d40SFabiano Rosas 
1419f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(cmpeq)
1420f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(cmpgtu)
1421f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(cmpgts)
1422f0984d40SFabiano Rosas 
1423f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(mins)
1424f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(minu)
1425f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(maxs)
1426f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(maxu)
1427f0984d40SFabiano Rosas 
1428f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(subn)
1429f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(addn)
1430f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(subu)
1431f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(addu)
1432f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(subs)
1433f0984d40SFabiano Rosas IWMMXT_OP_ENV_SIZE(adds)
1434f0984d40SFabiano Rosas 
1435f0984d40SFabiano Rosas IWMMXT_OP_ENV(avgb0)
1436f0984d40SFabiano Rosas IWMMXT_OP_ENV(avgb1)
1437f0984d40SFabiano Rosas IWMMXT_OP_ENV(avgw0)
1438f0984d40SFabiano Rosas IWMMXT_OP_ENV(avgw1)
1439f0984d40SFabiano Rosas 
1440f0984d40SFabiano Rosas IWMMXT_OP_ENV(packuw)
1441f0984d40SFabiano Rosas IWMMXT_OP_ENV(packul)
1442f0984d40SFabiano Rosas IWMMXT_OP_ENV(packuq)
1443f0984d40SFabiano Rosas IWMMXT_OP_ENV(packsw)
1444f0984d40SFabiano Rosas IWMMXT_OP_ENV(packsl)
1445f0984d40SFabiano Rosas IWMMXT_OP_ENV(packsq)
1446f0984d40SFabiano Rosas 
1447f0984d40SFabiano Rosas static void gen_op_iwmmxt_set_mup(void)
1448f0984d40SFabiano Rosas {
1449f0984d40SFabiano Rosas     TCGv_i32 tmp;
1450f0984d40SFabiano Rosas     tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
1451f0984d40SFabiano Rosas     tcg_gen_ori_i32(tmp, tmp, 2);
1452f0984d40SFabiano Rosas     store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
1453f0984d40SFabiano Rosas }
1454f0984d40SFabiano Rosas 
1455f0984d40SFabiano Rosas static void gen_op_iwmmxt_set_cup(void)
1456f0984d40SFabiano Rosas {
1457f0984d40SFabiano Rosas     TCGv_i32 tmp;
1458f0984d40SFabiano Rosas     tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
1459f0984d40SFabiano Rosas     tcg_gen_ori_i32(tmp, tmp, 1);
1460f0984d40SFabiano Rosas     store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
1461f0984d40SFabiano Rosas }
1462f0984d40SFabiano Rosas 
1463f0984d40SFabiano Rosas static void gen_op_iwmmxt_setpsr_nz(void)
1464f0984d40SFabiano Rosas {
1465f0984d40SFabiano Rosas     TCGv_i32 tmp = tcg_temp_new_i32();
1466f0984d40SFabiano Rosas     gen_helper_iwmmxt_setpsr_nz(tmp, cpu_M0);
1467f0984d40SFabiano Rosas     store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCASF]);
1468f0984d40SFabiano Rosas }
1469f0984d40SFabiano Rosas 
1470f0984d40SFabiano Rosas static inline void gen_op_iwmmxt_addl_M0_wRn(int rn)
1471f0984d40SFabiano Rosas {
1472f0984d40SFabiano Rosas     iwmmxt_load_reg(cpu_V1, rn);
1473f0984d40SFabiano Rosas     tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
1474f0984d40SFabiano Rosas     tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1475f0984d40SFabiano Rosas }
1476f0984d40SFabiano Rosas 
1477f0984d40SFabiano Rosas static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn,
1478f0984d40SFabiano Rosas                                      TCGv_i32 dest)
1479f0984d40SFabiano Rosas {
1480f0984d40SFabiano Rosas     int rd;
1481f0984d40SFabiano Rosas     uint32_t offset;
1482f0984d40SFabiano Rosas     TCGv_i32 tmp;
1483f0984d40SFabiano Rosas 
1484f0984d40SFabiano Rosas     rd = (insn >> 16) & 0xf;
1485f0984d40SFabiano Rosas     tmp = load_reg(s, rd);
1486f0984d40SFabiano Rosas 
1487f0984d40SFabiano Rosas     offset = (insn & 0xff) << ((insn >> 7) & 2);
1488f0984d40SFabiano Rosas     if (insn & (1 << 24)) {
1489f0984d40SFabiano Rosas         /* Pre indexed */
1490f0984d40SFabiano Rosas         if (insn & (1 << 23))
1491f0984d40SFabiano Rosas             tcg_gen_addi_i32(tmp, tmp, offset);
1492f0984d40SFabiano Rosas         else
1493f0984d40SFabiano Rosas             tcg_gen_addi_i32(tmp, tmp, -offset);
1494f0984d40SFabiano Rosas         tcg_gen_mov_i32(dest, tmp);
1495f0984d40SFabiano Rosas         if (insn & (1 << 21))
1496f0984d40SFabiano Rosas             store_reg(s, rd, tmp);
1497f0984d40SFabiano Rosas         else
1498f0984d40SFabiano Rosas             tcg_temp_free_i32(tmp);
1499f0984d40SFabiano Rosas     } else if (insn & (1 << 21)) {
1500f0984d40SFabiano Rosas         /* Post indexed */
1501f0984d40SFabiano Rosas         tcg_gen_mov_i32(dest, tmp);
1502f0984d40SFabiano Rosas         if (insn & (1 << 23))
1503f0984d40SFabiano Rosas             tcg_gen_addi_i32(tmp, tmp, offset);
1504f0984d40SFabiano Rosas         else
1505f0984d40SFabiano Rosas             tcg_gen_addi_i32(tmp, tmp, -offset);
1506f0984d40SFabiano Rosas         store_reg(s, rd, tmp);
1507f0984d40SFabiano Rosas     } else if (!(insn & (1 << 23)))
1508f0984d40SFabiano Rosas         return 1;
1509f0984d40SFabiano Rosas     return 0;
1510f0984d40SFabiano Rosas }
1511f0984d40SFabiano Rosas 
1512f0984d40SFabiano Rosas static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv_i32 dest)
1513f0984d40SFabiano Rosas {
1514f0984d40SFabiano Rosas     int rd = (insn >> 0) & 0xf;
1515f0984d40SFabiano Rosas     TCGv_i32 tmp;
1516f0984d40SFabiano Rosas 
1517f0984d40SFabiano Rosas     if (insn & (1 << 8)) {
1518f0984d40SFabiano Rosas         if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) {
1519f0984d40SFabiano Rosas             return 1;
1520f0984d40SFabiano Rosas         } else {
1521f0984d40SFabiano Rosas             tmp = iwmmxt_load_creg(rd);
1522f0984d40SFabiano Rosas         }
1523f0984d40SFabiano Rosas     } else {
1524f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
1525f0984d40SFabiano Rosas         iwmmxt_load_reg(cpu_V0, rd);
1526f0984d40SFabiano Rosas         tcg_gen_extrl_i64_i32(tmp, cpu_V0);
1527f0984d40SFabiano Rosas     }
1528f0984d40SFabiano Rosas     tcg_gen_andi_i32(tmp, tmp, mask);
1529f0984d40SFabiano Rosas     tcg_gen_mov_i32(dest, tmp);
1530f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
1531f0984d40SFabiano Rosas     return 0;
1532f0984d40SFabiano Rosas }
1533f0984d40SFabiano Rosas 
1534f0984d40SFabiano Rosas /* Disassemble an iwMMXt instruction.  Returns nonzero if an error occurred
1535f0984d40SFabiano Rosas    (ie. an undefined instruction).  */
1536f0984d40SFabiano Rosas static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
1537f0984d40SFabiano Rosas {
1538f0984d40SFabiano Rosas     int rd, wrd;
1539f0984d40SFabiano Rosas     int rdhi, rdlo, rd0, rd1, i;
1540f0984d40SFabiano Rosas     TCGv_i32 addr;
1541f0984d40SFabiano Rosas     TCGv_i32 tmp, tmp2, tmp3;
1542f0984d40SFabiano Rosas 
1543f0984d40SFabiano Rosas     if ((insn & 0x0e000e00) == 0x0c000000) {
1544f0984d40SFabiano Rosas         if ((insn & 0x0fe00ff0) == 0x0c400000) {
1545f0984d40SFabiano Rosas             wrd = insn & 0xf;
1546f0984d40SFabiano Rosas             rdlo = (insn >> 12) & 0xf;
1547f0984d40SFabiano Rosas             rdhi = (insn >> 16) & 0xf;
1548f0984d40SFabiano Rosas             if (insn & ARM_CP_RW_BIT) {                         /* TMRRC */
1549f0984d40SFabiano Rosas                 iwmmxt_load_reg(cpu_V0, wrd);
1550f0984d40SFabiano Rosas                 tcg_gen_extrl_i64_i32(cpu_R[rdlo], cpu_V0);
1551f0984d40SFabiano Rosas                 tcg_gen_extrh_i64_i32(cpu_R[rdhi], cpu_V0);
1552f0984d40SFabiano Rosas             } else {                                    /* TMCRR */
1553f0984d40SFabiano Rosas                 tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
1554f0984d40SFabiano Rosas                 iwmmxt_store_reg(cpu_V0, wrd);
1555f0984d40SFabiano Rosas                 gen_op_iwmmxt_set_mup();
1556f0984d40SFabiano Rosas             }
1557f0984d40SFabiano Rosas             return 0;
1558f0984d40SFabiano Rosas         }
1559f0984d40SFabiano Rosas 
1560f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1561f0984d40SFabiano Rosas         addr = tcg_temp_new_i32();
1562f0984d40SFabiano Rosas         if (gen_iwmmxt_address(s, insn, addr)) {
1563f0984d40SFabiano Rosas             tcg_temp_free_i32(addr);
1564f0984d40SFabiano Rosas             return 1;
1565f0984d40SFabiano Rosas         }
1566f0984d40SFabiano Rosas         if (insn & ARM_CP_RW_BIT) {
1567f0984d40SFabiano Rosas             if ((insn >> 28) == 0xf) {                  /* WLDRW wCx */
1568f0984d40SFabiano Rosas                 tmp = tcg_temp_new_i32();
1569f0984d40SFabiano Rosas                 gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
1570f0984d40SFabiano Rosas                 iwmmxt_store_creg(wrd, tmp);
1571f0984d40SFabiano Rosas             } else {
1572f0984d40SFabiano Rosas                 i = 1;
1573f0984d40SFabiano Rosas                 if (insn & (1 << 8)) {
1574f0984d40SFabiano Rosas                     if (insn & (1 << 22)) {             /* WLDRD */
1575f0984d40SFabiano Rosas                         gen_aa32_ld64(s, cpu_M0, addr, get_mem_index(s));
1576f0984d40SFabiano Rosas                         i = 0;
1577f0984d40SFabiano Rosas                     } else {                            /* WLDRW wRd */
1578f0984d40SFabiano Rosas                         tmp = tcg_temp_new_i32();
1579f0984d40SFabiano Rosas                         gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
1580f0984d40SFabiano Rosas                     }
1581f0984d40SFabiano Rosas                 } else {
1582f0984d40SFabiano Rosas                     tmp = tcg_temp_new_i32();
1583f0984d40SFabiano Rosas                     if (insn & (1 << 22)) {             /* WLDRH */
1584f0984d40SFabiano Rosas                         gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
1585f0984d40SFabiano Rosas                     } else {                            /* WLDRB */
1586f0984d40SFabiano Rosas                         gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
1587f0984d40SFabiano Rosas                     }
1588f0984d40SFabiano Rosas                 }
1589f0984d40SFabiano Rosas                 if (i) {
1590f0984d40SFabiano Rosas                     tcg_gen_extu_i32_i64(cpu_M0, tmp);
1591f0984d40SFabiano Rosas                     tcg_temp_free_i32(tmp);
1592f0984d40SFabiano Rosas                 }
1593f0984d40SFabiano Rosas                 gen_op_iwmmxt_movq_wRn_M0(wrd);
1594f0984d40SFabiano Rosas             }
1595f0984d40SFabiano Rosas         } else {
1596f0984d40SFabiano Rosas             if ((insn >> 28) == 0xf) {                  /* WSTRW wCx */
1597f0984d40SFabiano Rosas                 tmp = iwmmxt_load_creg(wrd);
1598f0984d40SFabiano Rosas                 gen_aa32_st32(s, tmp, addr, get_mem_index(s));
1599f0984d40SFabiano Rosas             } else {
1600f0984d40SFabiano Rosas                 gen_op_iwmmxt_movq_M0_wRn(wrd);
1601f0984d40SFabiano Rosas                 tmp = tcg_temp_new_i32();
1602f0984d40SFabiano Rosas                 if (insn & (1 << 8)) {
1603f0984d40SFabiano Rosas                     if (insn & (1 << 22)) {             /* WSTRD */
1604f0984d40SFabiano Rosas                         gen_aa32_st64(s, cpu_M0, addr, get_mem_index(s));
1605f0984d40SFabiano Rosas                     } else {                            /* WSTRW wRd */
1606f0984d40SFabiano Rosas                         tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1607f0984d40SFabiano Rosas                         gen_aa32_st32(s, tmp, addr, get_mem_index(s));
1608f0984d40SFabiano Rosas                     }
1609f0984d40SFabiano Rosas                 } else {
1610f0984d40SFabiano Rosas                     if (insn & (1 << 22)) {             /* WSTRH */
1611f0984d40SFabiano Rosas                         tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1612f0984d40SFabiano Rosas                         gen_aa32_st16(s, tmp, addr, get_mem_index(s));
1613f0984d40SFabiano Rosas                     } else {                            /* WSTRB */
1614f0984d40SFabiano Rosas                         tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1615f0984d40SFabiano Rosas                         gen_aa32_st8(s, tmp, addr, get_mem_index(s));
1616f0984d40SFabiano Rosas                     }
1617f0984d40SFabiano Rosas                 }
1618f0984d40SFabiano Rosas             }
1619f0984d40SFabiano Rosas             tcg_temp_free_i32(tmp);
1620f0984d40SFabiano Rosas         }
1621f0984d40SFabiano Rosas         tcg_temp_free_i32(addr);
1622f0984d40SFabiano Rosas         return 0;
1623f0984d40SFabiano Rosas     }
1624f0984d40SFabiano Rosas 
1625f0984d40SFabiano Rosas     if ((insn & 0x0f000000) != 0x0e000000)
1626f0984d40SFabiano Rosas         return 1;
1627f0984d40SFabiano Rosas 
1628f0984d40SFabiano Rosas     switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
1629f0984d40SFabiano Rosas     case 0x000:                                                 /* WOR */
1630f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1631f0984d40SFabiano Rosas         rd0 = (insn >> 0) & 0xf;
1632f0984d40SFabiano Rosas         rd1 = (insn >> 16) & 0xf;
1633f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1634f0984d40SFabiano Rosas         gen_op_iwmmxt_orq_M0_wRn(rd1);
1635f0984d40SFabiano Rosas         gen_op_iwmmxt_setpsr_nz();
1636f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1637f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1638f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
1639f0984d40SFabiano Rosas         break;
1640f0984d40SFabiano Rosas     case 0x011:                                                 /* TMCR */
1641f0984d40SFabiano Rosas         if (insn & 0xf)
1642f0984d40SFabiano Rosas             return 1;
1643f0984d40SFabiano Rosas         rd = (insn >> 12) & 0xf;
1644f0984d40SFabiano Rosas         wrd = (insn >> 16) & 0xf;
1645f0984d40SFabiano Rosas         switch (wrd) {
1646f0984d40SFabiano Rosas         case ARM_IWMMXT_wCID:
1647f0984d40SFabiano Rosas         case ARM_IWMMXT_wCASF:
1648f0984d40SFabiano Rosas             break;
1649f0984d40SFabiano Rosas         case ARM_IWMMXT_wCon:
1650f0984d40SFabiano Rosas             gen_op_iwmmxt_set_cup();
1651f0984d40SFabiano Rosas             /* Fall through.  */
1652f0984d40SFabiano Rosas         case ARM_IWMMXT_wCSSF:
1653f0984d40SFabiano Rosas             tmp = iwmmxt_load_creg(wrd);
1654f0984d40SFabiano Rosas             tmp2 = load_reg(s, rd);
1655f0984d40SFabiano Rosas             tcg_gen_andc_i32(tmp, tmp, tmp2);
1656f0984d40SFabiano Rosas             tcg_temp_free_i32(tmp2);
1657f0984d40SFabiano Rosas             iwmmxt_store_creg(wrd, tmp);
1658f0984d40SFabiano Rosas             break;
1659f0984d40SFabiano Rosas         case ARM_IWMMXT_wCGR0:
1660f0984d40SFabiano Rosas         case ARM_IWMMXT_wCGR1:
1661f0984d40SFabiano Rosas         case ARM_IWMMXT_wCGR2:
1662f0984d40SFabiano Rosas         case ARM_IWMMXT_wCGR3:
1663f0984d40SFabiano Rosas             gen_op_iwmmxt_set_cup();
1664f0984d40SFabiano Rosas             tmp = load_reg(s, rd);
1665f0984d40SFabiano Rosas             iwmmxt_store_creg(wrd, tmp);
1666f0984d40SFabiano Rosas             break;
1667f0984d40SFabiano Rosas         default:
1668f0984d40SFabiano Rosas             return 1;
1669f0984d40SFabiano Rosas         }
1670f0984d40SFabiano Rosas         break;
1671f0984d40SFabiano Rosas     case 0x100:                                                 /* WXOR */
1672f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1673f0984d40SFabiano Rosas         rd0 = (insn >> 0) & 0xf;
1674f0984d40SFabiano Rosas         rd1 = (insn >> 16) & 0xf;
1675f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1676f0984d40SFabiano Rosas         gen_op_iwmmxt_xorq_M0_wRn(rd1);
1677f0984d40SFabiano Rosas         gen_op_iwmmxt_setpsr_nz();
1678f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1679f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1680f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
1681f0984d40SFabiano Rosas         break;
1682f0984d40SFabiano Rosas     case 0x111:                                                 /* TMRC */
1683f0984d40SFabiano Rosas         if (insn & 0xf)
1684f0984d40SFabiano Rosas             return 1;
1685f0984d40SFabiano Rosas         rd = (insn >> 12) & 0xf;
1686f0984d40SFabiano Rosas         wrd = (insn >> 16) & 0xf;
1687f0984d40SFabiano Rosas         tmp = iwmmxt_load_creg(wrd);
1688f0984d40SFabiano Rosas         store_reg(s, rd, tmp);
1689f0984d40SFabiano Rosas         break;
1690f0984d40SFabiano Rosas     case 0x300:                                                 /* WANDN */
1691f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1692f0984d40SFabiano Rosas         rd0 = (insn >> 0) & 0xf;
1693f0984d40SFabiano Rosas         rd1 = (insn >> 16) & 0xf;
1694f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1695f0984d40SFabiano Rosas         tcg_gen_neg_i64(cpu_M0, cpu_M0);
1696f0984d40SFabiano Rosas         gen_op_iwmmxt_andq_M0_wRn(rd1);
1697f0984d40SFabiano Rosas         gen_op_iwmmxt_setpsr_nz();
1698f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1699f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1700f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
1701f0984d40SFabiano Rosas         break;
1702f0984d40SFabiano Rosas     case 0x200:                                                 /* WAND */
1703f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1704f0984d40SFabiano Rosas         rd0 = (insn >> 0) & 0xf;
1705f0984d40SFabiano Rosas         rd1 = (insn >> 16) & 0xf;
1706f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1707f0984d40SFabiano Rosas         gen_op_iwmmxt_andq_M0_wRn(rd1);
1708f0984d40SFabiano Rosas         gen_op_iwmmxt_setpsr_nz();
1709f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1710f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1711f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
1712f0984d40SFabiano Rosas         break;
1713f0984d40SFabiano Rosas     case 0x810: case 0xa10:                             /* WMADD */
1714f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1715f0984d40SFabiano Rosas         rd0 = (insn >> 0) & 0xf;
1716f0984d40SFabiano Rosas         rd1 = (insn >> 16) & 0xf;
1717f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1718f0984d40SFabiano Rosas         if (insn & (1 << 21))
1719f0984d40SFabiano Rosas             gen_op_iwmmxt_maddsq_M0_wRn(rd1);
1720f0984d40SFabiano Rosas         else
1721f0984d40SFabiano Rosas             gen_op_iwmmxt_madduq_M0_wRn(rd1);
1722f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1723f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1724f0984d40SFabiano Rosas         break;
1725f0984d40SFabiano Rosas     case 0x10e: case 0x50e: case 0x90e: case 0xd0e:     /* WUNPCKIL */
1726f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1727f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
1728f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
1729f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1730f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
1731f0984d40SFabiano Rosas         case 0:
1732f0984d40SFabiano Rosas             gen_op_iwmmxt_unpacklb_M0_wRn(rd1);
1733f0984d40SFabiano Rosas             break;
1734f0984d40SFabiano Rosas         case 1:
1735f0984d40SFabiano Rosas             gen_op_iwmmxt_unpacklw_M0_wRn(rd1);
1736f0984d40SFabiano Rosas             break;
1737f0984d40SFabiano Rosas         case 2:
1738f0984d40SFabiano Rosas             gen_op_iwmmxt_unpackll_M0_wRn(rd1);
1739f0984d40SFabiano Rosas             break;
1740f0984d40SFabiano Rosas         case 3:
1741f0984d40SFabiano Rosas             return 1;
1742f0984d40SFabiano Rosas         }
1743f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1744f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1745f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
1746f0984d40SFabiano Rosas         break;
1747f0984d40SFabiano Rosas     case 0x10c: case 0x50c: case 0x90c: case 0xd0c:     /* WUNPCKIH */
1748f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1749f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
1750f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
1751f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1752f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
1753f0984d40SFabiano Rosas         case 0:
1754f0984d40SFabiano Rosas             gen_op_iwmmxt_unpackhb_M0_wRn(rd1);
1755f0984d40SFabiano Rosas             break;
1756f0984d40SFabiano Rosas         case 1:
1757f0984d40SFabiano Rosas             gen_op_iwmmxt_unpackhw_M0_wRn(rd1);
1758f0984d40SFabiano Rosas             break;
1759f0984d40SFabiano Rosas         case 2:
1760f0984d40SFabiano Rosas             gen_op_iwmmxt_unpackhl_M0_wRn(rd1);
1761f0984d40SFabiano Rosas             break;
1762f0984d40SFabiano Rosas         case 3:
1763f0984d40SFabiano Rosas             return 1;
1764f0984d40SFabiano Rosas         }
1765f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1766f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1767f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
1768f0984d40SFabiano Rosas         break;
1769f0984d40SFabiano Rosas     case 0x012: case 0x112: case 0x412: case 0x512:     /* WSAD */
1770f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1771f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
1772f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
1773f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1774f0984d40SFabiano Rosas         if (insn & (1 << 22))
1775f0984d40SFabiano Rosas             gen_op_iwmmxt_sadw_M0_wRn(rd1);
1776f0984d40SFabiano Rosas         else
1777f0984d40SFabiano Rosas             gen_op_iwmmxt_sadb_M0_wRn(rd1);
1778f0984d40SFabiano Rosas         if (!(insn & (1 << 20)))
1779f0984d40SFabiano Rosas             gen_op_iwmmxt_addl_M0_wRn(wrd);
1780f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1781f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1782f0984d40SFabiano Rosas         break;
1783f0984d40SFabiano Rosas     case 0x010: case 0x110: case 0x210: case 0x310:     /* WMUL */
1784f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1785f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
1786f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
1787f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1788f0984d40SFabiano Rosas         if (insn & (1 << 21)) {
1789f0984d40SFabiano Rosas             if (insn & (1 << 20))
1790f0984d40SFabiano Rosas                 gen_op_iwmmxt_mulshw_M0_wRn(rd1);
1791f0984d40SFabiano Rosas             else
1792f0984d40SFabiano Rosas                 gen_op_iwmmxt_mulslw_M0_wRn(rd1);
1793f0984d40SFabiano Rosas         } else {
1794f0984d40SFabiano Rosas             if (insn & (1 << 20))
1795f0984d40SFabiano Rosas                 gen_op_iwmmxt_muluhw_M0_wRn(rd1);
1796f0984d40SFabiano Rosas             else
1797f0984d40SFabiano Rosas                 gen_op_iwmmxt_mululw_M0_wRn(rd1);
1798f0984d40SFabiano Rosas         }
1799f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1800f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1801f0984d40SFabiano Rosas         break;
1802f0984d40SFabiano Rosas     case 0x410: case 0x510: case 0x610: case 0x710:     /* WMAC */
1803f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1804f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
1805f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
1806f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1807f0984d40SFabiano Rosas         if (insn & (1 << 21))
1808f0984d40SFabiano Rosas             gen_op_iwmmxt_macsw_M0_wRn(rd1);
1809f0984d40SFabiano Rosas         else
1810f0984d40SFabiano Rosas             gen_op_iwmmxt_macuw_M0_wRn(rd1);
1811f0984d40SFabiano Rosas         if (!(insn & (1 << 20))) {
1812f0984d40SFabiano Rosas             iwmmxt_load_reg(cpu_V1, wrd);
1813f0984d40SFabiano Rosas             tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1814f0984d40SFabiano Rosas         }
1815f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1816f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1817f0984d40SFabiano Rosas         break;
1818f0984d40SFabiano Rosas     case 0x006: case 0x406: case 0x806: case 0xc06:     /* WCMPEQ */
1819f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1820f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
1821f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
1822f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1823f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
1824f0984d40SFabiano Rosas         case 0:
1825f0984d40SFabiano Rosas             gen_op_iwmmxt_cmpeqb_M0_wRn(rd1);
1826f0984d40SFabiano Rosas             break;
1827f0984d40SFabiano Rosas         case 1:
1828f0984d40SFabiano Rosas             gen_op_iwmmxt_cmpeqw_M0_wRn(rd1);
1829f0984d40SFabiano Rosas             break;
1830f0984d40SFabiano Rosas         case 2:
1831f0984d40SFabiano Rosas             gen_op_iwmmxt_cmpeql_M0_wRn(rd1);
1832f0984d40SFabiano Rosas             break;
1833f0984d40SFabiano Rosas         case 3:
1834f0984d40SFabiano Rosas             return 1;
1835f0984d40SFabiano Rosas         }
1836f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1837f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1838f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
1839f0984d40SFabiano Rosas         break;
1840f0984d40SFabiano Rosas     case 0x800: case 0x900: case 0xc00: case 0xd00:     /* WAVG2 */
1841f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1842f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
1843f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
1844f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1845f0984d40SFabiano Rosas         if (insn & (1 << 22)) {
1846f0984d40SFabiano Rosas             if (insn & (1 << 20))
1847f0984d40SFabiano Rosas                 gen_op_iwmmxt_avgw1_M0_wRn(rd1);
1848f0984d40SFabiano Rosas             else
1849f0984d40SFabiano Rosas                 gen_op_iwmmxt_avgw0_M0_wRn(rd1);
1850f0984d40SFabiano Rosas         } else {
1851f0984d40SFabiano Rosas             if (insn & (1 << 20))
1852f0984d40SFabiano Rosas                 gen_op_iwmmxt_avgb1_M0_wRn(rd1);
1853f0984d40SFabiano Rosas             else
1854f0984d40SFabiano Rosas                 gen_op_iwmmxt_avgb0_M0_wRn(rd1);
1855f0984d40SFabiano Rosas         }
1856f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1857f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1858f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
1859f0984d40SFabiano Rosas         break;
1860f0984d40SFabiano Rosas     case 0x802: case 0x902: case 0xa02: case 0xb02:     /* WALIGNR */
1861f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
1862f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
1863f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
1864f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
1865f0984d40SFabiano Rosas         tmp = iwmmxt_load_creg(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
1866f0984d40SFabiano Rosas         tcg_gen_andi_i32(tmp, tmp, 7);
1867f0984d40SFabiano Rosas         iwmmxt_load_reg(cpu_V1, rd1);
1868f0984d40SFabiano Rosas         gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
1869f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
1870f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1871f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1872f0984d40SFabiano Rosas         break;
1873f0984d40SFabiano Rosas     case 0x601: case 0x605: case 0x609: case 0x60d:     /* TINSR */
1874f0984d40SFabiano Rosas         if (((insn >> 6) & 3) == 3)
1875f0984d40SFabiano Rosas             return 1;
1876f0984d40SFabiano Rosas         rd = (insn >> 12) & 0xf;
1877f0984d40SFabiano Rosas         wrd = (insn >> 16) & 0xf;
1878f0984d40SFabiano Rosas         tmp = load_reg(s, rd);
1879f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(wrd);
1880f0984d40SFabiano Rosas         switch ((insn >> 6) & 3) {
1881f0984d40SFabiano Rosas         case 0:
1882f0984d40SFabiano Rosas             tmp2 = tcg_constant_i32(0xff);
1883f0984d40SFabiano Rosas             tmp3 = tcg_constant_i32((insn & 7) << 3);
1884f0984d40SFabiano Rosas             break;
1885f0984d40SFabiano Rosas         case 1:
1886f0984d40SFabiano Rosas             tmp2 = tcg_constant_i32(0xffff);
1887f0984d40SFabiano Rosas             tmp3 = tcg_constant_i32((insn & 3) << 4);
1888f0984d40SFabiano Rosas             break;
1889f0984d40SFabiano Rosas         case 2:
1890f0984d40SFabiano Rosas             tmp2 = tcg_constant_i32(0xffffffff);
1891f0984d40SFabiano Rosas             tmp3 = tcg_constant_i32((insn & 1) << 5);
1892f0984d40SFabiano Rosas             break;
1893f0984d40SFabiano Rosas         default:
1894f0984d40SFabiano Rosas             g_assert_not_reached();
1895f0984d40SFabiano Rosas         }
1896f0984d40SFabiano Rosas         gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3);
1897f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
1898f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1899f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1900f0984d40SFabiano Rosas         break;
1901f0984d40SFabiano Rosas     case 0x107: case 0x507: case 0x907: case 0xd07:     /* TEXTRM */
1902f0984d40SFabiano Rosas         rd = (insn >> 12) & 0xf;
1903f0984d40SFabiano Rosas         wrd = (insn >> 16) & 0xf;
1904f0984d40SFabiano Rosas         if (rd == 15 || ((insn >> 22) & 3) == 3)
1905f0984d40SFabiano Rosas             return 1;
1906f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(wrd);
1907f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
1908f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
1909f0984d40SFabiano Rosas         case 0:
1910f0984d40SFabiano Rosas             tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3);
1911f0984d40SFabiano Rosas             tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1912f0984d40SFabiano Rosas             if (insn & 8) {
1913f0984d40SFabiano Rosas                 tcg_gen_ext8s_i32(tmp, tmp);
1914f0984d40SFabiano Rosas             } else {
1915f0984d40SFabiano Rosas                 tcg_gen_andi_i32(tmp, tmp, 0xff);
1916f0984d40SFabiano Rosas             }
1917f0984d40SFabiano Rosas             break;
1918f0984d40SFabiano Rosas         case 1:
1919f0984d40SFabiano Rosas             tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 3) << 4);
1920f0984d40SFabiano Rosas             tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1921f0984d40SFabiano Rosas             if (insn & 8) {
1922f0984d40SFabiano Rosas                 tcg_gen_ext16s_i32(tmp, tmp);
1923f0984d40SFabiano Rosas             } else {
1924f0984d40SFabiano Rosas                 tcg_gen_andi_i32(tmp, tmp, 0xffff);
1925f0984d40SFabiano Rosas             }
1926f0984d40SFabiano Rosas             break;
1927f0984d40SFabiano Rosas         case 2:
1928f0984d40SFabiano Rosas             tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 1) << 5);
1929f0984d40SFabiano Rosas             tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1930f0984d40SFabiano Rosas             break;
1931f0984d40SFabiano Rosas         }
1932f0984d40SFabiano Rosas         store_reg(s, rd, tmp);
1933f0984d40SFabiano Rosas         break;
1934f0984d40SFabiano Rosas     case 0x117: case 0x517: case 0x917: case 0xd17:     /* TEXTRC */
1935f0984d40SFabiano Rosas         if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3)
1936f0984d40SFabiano Rosas             return 1;
1937f0984d40SFabiano Rosas         tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
1938f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
1939f0984d40SFabiano Rosas         case 0:
1940f0984d40SFabiano Rosas             tcg_gen_shri_i32(tmp, tmp, ((insn & 7) << 2) + 0);
1941f0984d40SFabiano Rosas             break;
1942f0984d40SFabiano Rosas         case 1:
1943f0984d40SFabiano Rosas             tcg_gen_shri_i32(tmp, tmp, ((insn & 3) << 3) + 4);
1944f0984d40SFabiano Rosas             break;
1945f0984d40SFabiano Rosas         case 2:
1946f0984d40SFabiano Rosas             tcg_gen_shri_i32(tmp, tmp, ((insn & 1) << 4) + 12);
1947f0984d40SFabiano Rosas             break;
1948f0984d40SFabiano Rosas         }
1949f0984d40SFabiano Rosas         tcg_gen_shli_i32(tmp, tmp, 28);
1950f0984d40SFabiano Rosas         gen_set_nzcv(tmp);
1951f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
1952f0984d40SFabiano Rosas         break;
1953f0984d40SFabiano Rosas     case 0x401: case 0x405: case 0x409: case 0x40d:     /* TBCST */
1954f0984d40SFabiano Rosas         if (((insn >> 6) & 3) == 3)
1955f0984d40SFabiano Rosas             return 1;
1956f0984d40SFabiano Rosas         rd = (insn >> 12) & 0xf;
1957f0984d40SFabiano Rosas         wrd = (insn >> 16) & 0xf;
1958f0984d40SFabiano Rosas         tmp = load_reg(s, rd);
1959f0984d40SFabiano Rosas         switch ((insn >> 6) & 3) {
1960f0984d40SFabiano Rosas         case 0:
1961f0984d40SFabiano Rosas             gen_helper_iwmmxt_bcstb(cpu_M0, tmp);
1962f0984d40SFabiano Rosas             break;
1963f0984d40SFabiano Rosas         case 1:
1964f0984d40SFabiano Rosas             gen_helper_iwmmxt_bcstw(cpu_M0, tmp);
1965f0984d40SFabiano Rosas             break;
1966f0984d40SFabiano Rosas         case 2:
1967f0984d40SFabiano Rosas             gen_helper_iwmmxt_bcstl(cpu_M0, tmp);
1968f0984d40SFabiano Rosas             break;
1969f0984d40SFabiano Rosas         }
1970f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
1971f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
1972f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
1973f0984d40SFabiano Rosas         break;
1974f0984d40SFabiano Rosas     case 0x113: case 0x513: case 0x913: case 0xd13:     /* TANDC */
1975f0984d40SFabiano Rosas         if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
1976f0984d40SFabiano Rosas             return 1;
1977f0984d40SFabiano Rosas         tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
1978f0984d40SFabiano Rosas         tmp2 = tcg_temp_new_i32();
1979f0984d40SFabiano Rosas         tcg_gen_mov_i32(tmp2, tmp);
1980f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
1981f0984d40SFabiano Rosas         case 0:
1982f0984d40SFabiano Rosas             for (i = 0; i < 7; i ++) {
1983f0984d40SFabiano Rosas                 tcg_gen_shli_i32(tmp2, tmp2, 4);
1984f0984d40SFabiano Rosas                 tcg_gen_and_i32(tmp, tmp, tmp2);
1985f0984d40SFabiano Rosas             }
1986f0984d40SFabiano Rosas             break;
1987f0984d40SFabiano Rosas         case 1:
1988f0984d40SFabiano Rosas             for (i = 0; i < 3; i ++) {
1989f0984d40SFabiano Rosas                 tcg_gen_shli_i32(tmp2, tmp2, 8);
1990f0984d40SFabiano Rosas                 tcg_gen_and_i32(tmp, tmp, tmp2);
1991f0984d40SFabiano Rosas             }
1992f0984d40SFabiano Rosas             break;
1993f0984d40SFabiano Rosas         case 2:
1994f0984d40SFabiano Rosas             tcg_gen_shli_i32(tmp2, tmp2, 16);
1995f0984d40SFabiano Rosas             tcg_gen_and_i32(tmp, tmp, tmp2);
1996f0984d40SFabiano Rosas             break;
1997f0984d40SFabiano Rosas         }
1998f0984d40SFabiano Rosas         gen_set_nzcv(tmp);
1999f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp2);
2000f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
2001f0984d40SFabiano Rosas         break;
2002f0984d40SFabiano Rosas     case 0x01c: case 0x41c: case 0x81c: case 0xc1c:     /* WACC */
2003f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2004f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2005f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2006f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2007f0984d40SFabiano Rosas         case 0:
2008f0984d40SFabiano Rosas             gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
2009f0984d40SFabiano Rosas             break;
2010f0984d40SFabiano Rosas         case 1:
2011f0984d40SFabiano Rosas             gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
2012f0984d40SFabiano Rosas             break;
2013f0984d40SFabiano Rosas         case 2:
2014f0984d40SFabiano Rosas             gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
2015f0984d40SFabiano Rosas             break;
2016f0984d40SFabiano Rosas         case 3:
2017f0984d40SFabiano Rosas             return 1;
2018f0984d40SFabiano Rosas         }
2019f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2020f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2021f0984d40SFabiano Rosas         break;
2022f0984d40SFabiano Rosas     case 0x115: case 0x515: case 0x915: case 0xd15:     /* TORC */
2023f0984d40SFabiano Rosas         if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
2024f0984d40SFabiano Rosas             return 1;
2025f0984d40SFabiano Rosas         tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
2026f0984d40SFabiano Rosas         tmp2 = tcg_temp_new_i32();
2027f0984d40SFabiano Rosas         tcg_gen_mov_i32(tmp2, tmp);
2028f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2029f0984d40SFabiano Rosas         case 0:
2030f0984d40SFabiano Rosas             for (i = 0; i < 7; i ++) {
2031f0984d40SFabiano Rosas                 tcg_gen_shli_i32(tmp2, tmp2, 4);
2032f0984d40SFabiano Rosas                 tcg_gen_or_i32(tmp, tmp, tmp2);
2033f0984d40SFabiano Rosas             }
2034f0984d40SFabiano Rosas             break;
2035f0984d40SFabiano Rosas         case 1:
2036f0984d40SFabiano Rosas             for (i = 0; i < 3; i ++) {
2037f0984d40SFabiano Rosas                 tcg_gen_shli_i32(tmp2, tmp2, 8);
2038f0984d40SFabiano Rosas                 tcg_gen_or_i32(tmp, tmp, tmp2);
2039f0984d40SFabiano Rosas             }
2040f0984d40SFabiano Rosas             break;
2041f0984d40SFabiano Rosas         case 2:
2042f0984d40SFabiano Rosas             tcg_gen_shli_i32(tmp2, tmp2, 16);
2043f0984d40SFabiano Rosas             tcg_gen_or_i32(tmp, tmp, tmp2);
2044f0984d40SFabiano Rosas             break;
2045f0984d40SFabiano Rosas         }
2046f0984d40SFabiano Rosas         gen_set_nzcv(tmp);
2047f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp2);
2048f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
2049f0984d40SFabiano Rosas         break;
2050f0984d40SFabiano Rosas     case 0x103: case 0x503: case 0x903: case 0xd03:     /* TMOVMSK */
2051f0984d40SFabiano Rosas         rd = (insn >> 12) & 0xf;
2052f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2053f0984d40SFabiano Rosas         if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
2054f0984d40SFabiano Rosas             return 1;
2055f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2056f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
2057f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2058f0984d40SFabiano Rosas         case 0:
2059f0984d40SFabiano Rosas             gen_helper_iwmmxt_msbb(tmp, cpu_M0);
2060f0984d40SFabiano Rosas             break;
2061f0984d40SFabiano Rosas         case 1:
2062f0984d40SFabiano Rosas             gen_helper_iwmmxt_msbw(tmp, cpu_M0);
2063f0984d40SFabiano Rosas             break;
2064f0984d40SFabiano Rosas         case 2:
2065f0984d40SFabiano Rosas             gen_helper_iwmmxt_msbl(tmp, cpu_M0);
2066f0984d40SFabiano Rosas             break;
2067f0984d40SFabiano Rosas         }
2068f0984d40SFabiano Rosas         store_reg(s, rd, tmp);
2069f0984d40SFabiano Rosas         break;
2070f0984d40SFabiano Rosas     case 0x106: case 0x306: case 0x506: case 0x706:     /* WCMPGT */
2071f0984d40SFabiano Rosas     case 0x906: case 0xb06: case 0xd06: case 0xf06:
2072f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2073f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2074f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
2075f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2076f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2077f0984d40SFabiano Rosas         case 0:
2078f0984d40SFabiano Rosas             if (insn & (1 << 21))
2079f0984d40SFabiano Rosas                 gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1);
2080f0984d40SFabiano Rosas             else
2081f0984d40SFabiano Rosas                 gen_op_iwmmxt_cmpgtub_M0_wRn(rd1);
2082f0984d40SFabiano Rosas             break;
2083f0984d40SFabiano Rosas         case 1:
2084f0984d40SFabiano Rosas             if (insn & (1 << 21))
2085f0984d40SFabiano Rosas                 gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1);
2086f0984d40SFabiano Rosas             else
2087f0984d40SFabiano Rosas                 gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1);
2088f0984d40SFabiano Rosas             break;
2089f0984d40SFabiano Rosas         case 2:
2090f0984d40SFabiano Rosas             if (insn & (1 << 21))
2091f0984d40SFabiano Rosas                 gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1);
2092f0984d40SFabiano Rosas             else
2093f0984d40SFabiano Rosas                 gen_op_iwmmxt_cmpgtul_M0_wRn(rd1);
2094f0984d40SFabiano Rosas             break;
2095f0984d40SFabiano Rosas         case 3:
2096f0984d40SFabiano Rosas             return 1;
2097f0984d40SFabiano Rosas         }
2098f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2099f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2100f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2101f0984d40SFabiano Rosas         break;
2102f0984d40SFabiano Rosas     case 0x00e: case 0x20e: case 0x40e: case 0x60e:     /* WUNPCKEL */
2103f0984d40SFabiano Rosas     case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
2104f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2105f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2106f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2107f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2108f0984d40SFabiano Rosas         case 0:
2109f0984d40SFabiano Rosas             if (insn & (1 << 21))
2110f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpacklsb_M0();
2111f0984d40SFabiano Rosas             else
2112f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpacklub_M0();
2113f0984d40SFabiano Rosas             break;
2114f0984d40SFabiano Rosas         case 1:
2115f0984d40SFabiano Rosas             if (insn & (1 << 21))
2116f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpacklsw_M0();
2117f0984d40SFabiano Rosas             else
2118f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpackluw_M0();
2119f0984d40SFabiano Rosas             break;
2120f0984d40SFabiano Rosas         case 2:
2121f0984d40SFabiano Rosas             if (insn & (1 << 21))
2122f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpacklsl_M0();
2123f0984d40SFabiano Rosas             else
2124f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpacklul_M0();
2125f0984d40SFabiano Rosas             break;
2126f0984d40SFabiano Rosas         case 3:
2127f0984d40SFabiano Rosas             return 1;
2128f0984d40SFabiano Rosas         }
2129f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2130f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2131f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2132f0984d40SFabiano Rosas         break;
2133f0984d40SFabiano Rosas     case 0x00c: case 0x20c: case 0x40c: case 0x60c:     /* WUNPCKEH */
2134f0984d40SFabiano Rosas     case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
2135f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2136f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2137f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2138f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2139f0984d40SFabiano Rosas         case 0:
2140f0984d40SFabiano Rosas             if (insn & (1 << 21))
2141f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpackhsb_M0();
2142f0984d40SFabiano Rosas             else
2143f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpackhub_M0();
2144f0984d40SFabiano Rosas             break;
2145f0984d40SFabiano Rosas         case 1:
2146f0984d40SFabiano Rosas             if (insn & (1 << 21))
2147f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpackhsw_M0();
2148f0984d40SFabiano Rosas             else
2149f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpackhuw_M0();
2150f0984d40SFabiano Rosas             break;
2151f0984d40SFabiano Rosas         case 2:
2152f0984d40SFabiano Rosas             if (insn & (1 << 21))
2153f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpackhsl_M0();
2154f0984d40SFabiano Rosas             else
2155f0984d40SFabiano Rosas                 gen_op_iwmmxt_unpackhul_M0();
2156f0984d40SFabiano Rosas             break;
2157f0984d40SFabiano Rosas         case 3:
2158f0984d40SFabiano Rosas             return 1;
2159f0984d40SFabiano Rosas         }
2160f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2161f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2162f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2163f0984d40SFabiano Rosas         break;
2164f0984d40SFabiano Rosas     case 0x204: case 0x604: case 0xa04: case 0xe04:     /* WSRL */
2165f0984d40SFabiano Rosas     case 0x214: case 0x614: case 0xa14: case 0xe14:
2166f0984d40SFabiano Rosas         if (((insn >> 22) & 3) == 0)
2167f0984d40SFabiano Rosas             return 1;
2168f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2169f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2170f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2171f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
2172f0984d40SFabiano Rosas         if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2173f0984d40SFabiano Rosas             tcg_temp_free_i32(tmp);
2174f0984d40SFabiano Rosas             return 1;
2175f0984d40SFabiano Rosas         }
2176f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2177f0984d40SFabiano Rosas         case 1:
2178f0984d40SFabiano Rosas             gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp);
2179f0984d40SFabiano Rosas             break;
2180f0984d40SFabiano Rosas         case 2:
2181f0984d40SFabiano Rosas             gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp);
2182f0984d40SFabiano Rosas             break;
2183f0984d40SFabiano Rosas         case 3:
2184f0984d40SFabiano Rosas             gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp);
2185f0984d40SFabiano Rosas             break;
2186f0984d40SFabiano Rosas         }
2187f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
2188f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2189f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2190f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2191f0984d40SFabiano Rosas         break;
2192f0984d40SFabiano Rosas     case 0x004: case 0x404: case 0x804: case 0xc04:     /* WSRA */
2193f0984d40SFabiano Rosas     case 0x014: case 0x414: case 0x814: case 0xc14:
2194f0984d40SFabiano Rosas         if (((insn >> 22) & 3) == 0)
2195f0984d40SFabiano Rosas             return 1;
2196f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2197f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2198f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2199f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
2200f0984d40SFabiano Rosas         if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2201f0984d40SFabiano Rosas             tcg_temp_free_i32(tmp);
2202f0984d40SFabiano Rosas             return 1;
2203f0984d40SFabiano Rosas         }
2204f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2205f0984d40SFabiano Rosas         case 1:
2206f0984d40SFabiano Rosas             gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp);
2207f0984d40SFabiano Rosas             break;
2208f0984d40SFabiano Rosas         case 2:
2209f0984d40SFabiano Rosas             gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp);
2210f0984d40SFabiano Rosas             break;
2211f0984d40SFabiano Rosas         case 3:
2212f0984d40SFabiano Rosas             gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp);
2213f0984d40SFabiano Rosas             break;
2214f0984d40SFabiano Rosas         }
2215f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
2216f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2217f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2218f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2219f0984d40SFabiano Rosas         break;
2220f0984d40SFabiano Rosas     case 0x104: case 0x504: case 0x904: case 0xd04:     /* WSLL */
2221f0984d40SFabiano Rosas     case 0x114: case 0x514: case 0x914: case 0xd14:
2222f0984d40SFabiano Rosas         if (((insn >> 22) & 3) == 0)
2223f0984d40SFabiano Rosas             return 1;
2224f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2225f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2226f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2227f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
2228f0984d40SFabiano Rosas         if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2229f0984d40SFabiano Rosas             tcg_temp_free_i32(tmp);
2230f0984d40SFabiano Rosas             return 1;
2231f0984d40SFabiano Rosas         }
2232f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2233f0984d40SFabiano Rosas         case 1:
2234f0984d40SFabiano Rosas             gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp);
2235f0984d40SFabiano Rosas             break;
2236f0984d40SFabiano Rosas         case 2:
2237f0984d40SFabiano Rosas             gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp);
2238f0984d40SFabiano Rosas             break;
2239f0984d40SFabiano Rosas         case 3:
2240f0984d40SFabiano Rosas             gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp);
2241f0984d40SFabiano Rosas             break;
2242f0984d40SFabiano Rosas         }
2243f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
2244f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2245f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2246f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2247f0984d40SFabiano Rosas         break;
2248f0984d40SFabiano Rosas     case 0x304: case 0x704: case 0xb04: case 0xf04:     /* WROR */
2249f0984d40SFabiano Rosas     case 0x314: case 0x714: case 0xb14: case 0xf14:
2250f0984d40SFabiano Rosas         if (((insn >> 22) & 3) == 0)
2251f0984d40SFabiano Rosas             return 1;
2252f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2253f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2254f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2255f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
2256f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2257f0984d40SFabiano Rosas         case 1:
2258f0984d40SFabiano Rosas             if (gen_iwmmxt_shift(insn, 0xf, tmp)) {
2259f0984d40SFabiano Rosas                 tcg_temp_free_i32(tmp);
2260f0984d40SFabiano Rosas                 return 1;
2261f0984d40SFabiano Rosas             }
2262f0984d40SFabiano Rosas             gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp);
2263f0984d40SFabiano Rosas             break;
2264f0984d40SFabiano Rosas         case 2:
2265f0984d40SFabiano Rosas             if (gen_iwmmxt_shift(insn, 0x1f, tmp)) {
2266f0984d40SFabiano Rosas                 tcg_temp_free_i32(tmp);
2267f0984d40SFabiano Rosas                 return 1;
2268f0984d40SFabiano Rosas             }
2269f0984d40SFabiano Rosas             gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp);
2270f0984d40SFabiano Rosas             break;
2271f0984d40SFabiano Rosas         case 3:
2272f0984d40SFabiano Rosas             if (gen_iwmmxt_shift(insn, 0x3f, tmp)) {
2273f0984d40SFabiano Rosas                 tcg_temp_free_i32(tmp);
2274f0984d40SFabiano Rosas                 return 1;
2275f0984d40SFabiano Rosas             }
2276f0984d40SFabiano Rosas             gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp);
2277f0984d40SFabiano Rosas             break;
2278f0984d40SFabiano Rosas         }
2279f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
2280f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2281f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2282f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2283f0984d40SFabiano Rosas         break;
2284f0984d40SFabiano Rosas     case 0x116: case 0x316: case 0x516: case 0x716:     /* WMIN */
2285f0984d40SFabiano Rosas     case 0x916: case 0xb16: case 0xd16: case 0xf16:
2286f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2287f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2288f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
2289f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2290f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2291f0984d40SFabiano Rosas         case 0:
2292f0984d40SFabiano Rosas             if (insn & (1 << 21))
2293f0984d40SFabiano Rosas                 gen_op_iwmmxt_minsb_M0_wRn(rd1);
2294f0984d40SFabiano Rosas             else
2295f0984d40SFabiano Rosas                 gen_op_iwmmxt_minub_M0_wRn(rd1);
2296f0984d40SFabiano Rosas             break;
2297f0984d40SFabiano Rosas         case 1:
2298f0984d40SFabiano Rosas             if (insn & (1 << 21))
2299f0984d40SFabiano Rosas                 gen_op_iwmmxt_minsw_M0_wRn(rd1);
2300f0984d40SFabiano Rosas             else
2301f0984d40SFabiano Rosas                 gen_op_iwmmxt_minuw_M0_wRn(rd1);
2302f0984d40SFabiano Rosas             break;
2303f0984d40SFabiano Rosas         case 2:
2304f0984d40SFabiano Rosas             if (insn & (1 << 21))
2305f0984d40SFabiano Rosas                 gen_op_iwmmxt_minsl_M0_wRn(rd1);
2306f0984d40SFabiano Rosas             else
2307f0984d40SFabiano Rosas                 gen_op_iwmmxt_minul_M0_wRn(rd1);
2308f0984d40SFabiano Rosas             break;
2309f0984d40SFabiano Rosas         case 3:
2310f0984d40SFabiano Rosas             return 1;
2311f0984d40SFabiano Rosas         }
2312f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2313f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2314f0984d40SFabiano Rosas         break;
2315f0984d40SFabiano Rosas     case 0x016: case 0x216: case 0x416: case 0x616:     /* WMAX */
2316f0984d40SFabiano Rosas     case 0x816: case 0xa16: case 0xc16: case 0xe16:
2317f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2318f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2319f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
2320f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2321f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2322f0984d40SFabiano Rosas         case 0:
2323f0984d40SFabiano Rosas             if (insn & (1 << 21))
2324f0984d40SFabiano Rosas                 gen_op_iwmmxt_maxsb_M0_wRn(rd1);
2325f0984d40SFabiano Rosas             else
2326f0984d40SFabiano Rosas                 gen_op_iwmmxt_maxub_M0_wRn(rd1);
2327f0984d40SFabiano Rosas             break;
2328f0984d40SFabiano Rosas         case 1:
2329f0984d40SFabiano Rosas             if (insn & (1 << 21))
2330f0984d40SFabiano Rosas                 gen_op_iwmmxt_maxsw_M0_wRn(rd1);
2331f0984d40SFabiano Rosas             else
2332f0984d40SFabiano Rosas                 gen_op_iwmmxt_maxuw_M0_wRn(rd1);
2333f0984d40SFabiano Rosas             break;
2334f0984d40SFabiano Rosas         case 2:
2335f0984d40SFabiano Rosas             if (insn & (1 << 21))
2336f0984d40SFabiano Rosas                 gen_op_iwmmxt_maxsl_M0_wRn(rd1);
2337f0984d40SFabiano Rosas             else
2338f0984d40SFabiano Rosas                 gen_op_iwmmxt_maxul_M0_wRn(rd1);
2339f0984d40SFabiano Rosas             break;
2340f0984d40SFabiano Rosas         case 3:
2341f0984d40SFabiano Rosas             return 1;
2342f0984d40SFabiano Rosas         }
2343f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2344f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2345f0984d40SFabiano Rosas         break;
2346f0984d40SFabiano Rosas     case 0x002: case 0x102: case 0x202: case 0x302:     /* WALIGNI */
2347f0984d40SFabiano Rosas     case 0x402: case 0x502: case 0x602: case 0x702:
2348f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2349f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2350f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
2351f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2352f0984d40SFabiano Rosas         iwmmxt_load_reg(cpu_V1, rd1);
2353f0984d40SFabiano Rosas         gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1,
2354f0984d40SFabiano Rosas                                 tcg_constant_i32((insn >> 20) & 3));
2355f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2356f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2357f0984d40SFabiano Rosas         break;
2358f0984d40SFabiano Rosas     case 0x01a: case 0x11a: case 0x21a: case 0x31a:     /* WSUB */
2359f0984d40SFabiano Rosas     case 0x41a: case 0x51a: case 0x61a: case 0x71a:
2360f0984d40SFabiano Rosas     case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
2361f0984d40SFabiano Rosas     case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
2362f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2363f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2364f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
2365f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2366f0984d40SFabiano Rosas         switch ((insn >> 20) & 0xf) {
2367f0984d40SFabiano Rosas         case 0x0:
2368f0984d40SFabiano Rosas             gen_op_iwmmxt_subnb_M0_wRn(rd1);
2369f0984d40SFabiano Rosas             break;
2370f0984d40SFabiano Rosas         case 0x1:
2371f0984d40SFabiano Rosas             gen_op_iwmmxt_subub_M0_wRn(rd1);
2372f0984d40SFabiano Rosas             break;
2373f0984d40SFabiano Rosas         case 0x3:
2374f0984d40SFabiano Rosas             gen_op_iwmmxt_subsb_M0_wRn(rd1);
2375f0984d40SFabiano Rosas             break;
2376f0984d40SFabiano Rosas         case 0x4:
2377f0984d40SFabiano Rosas             gen_op_iwmmxt_subnw_M0_wRn(rd1);
2378f0984d40SFabiano Rosas             break;
2379f0984d40SFabiano Rosas         case 0x5:
2380f0984d40SFabiano Rosas             gen_op_iwmmxt_subuw_M0_wRn(rd1);
2381f0984d40SFabiano Rosas             break;
2382f0984d40SFabiano Rosas         case 0x7:
2383f0984d40SFabiano Rosas             gen_op_iwmmxt_subsw_M0_wRn(rd1);
2384f0984d40SFabiano Rosas             break;
2385f0984d40SFabiano Rosas         case 0x8:
2386f0984d40SFabiano Rosas             gen_op_iwmmxt_subnl_M0_wRn(rd1);
2387f0984d40SFabiano Rosas             break;
2388f0984d40SFabiano Rosas         case 0x9:
2389f0984d40SFabiano Rosas             gen_op_iwmmxt_subul_M0_wRn(rd1);
2390f0984d40SFabiano Rosas             break;
2391f0984d40SFabiano Rosas         case 0xb:
2392f0984d40SFabiano Rosas             gen_op_iwmmxt_subsl_M0_wRn(rd1);
2393f0984d40SFabiano Rosas             break;
2394f0984d40SFabiano Rosas         default:
2395f0984d40SFabiano Rosas             return 1;
2396f0984d40SFabiano Rosas         }
2397f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2398f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2399f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2400f0984d40SFabiano Rosas         break;
2401f0984d40SFabiano Rosas     case 0x01e: case 0x11e: case 0x21e: case 0x31e:     /* WSHUFH */
2402f0984d40SFabiano Rosas     case 0x41e: case 0x51e: case 0x61e: case 0x71e:
2403f0984d40SFabiano Rosas     case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
2404f0984d40SFabiano Rosas     case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
2405f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2406f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2407f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2408f0984d40SFabiano Rosas         tmp = tcg_constant_i32(((insn >> 16) & 0xf0) | (insn & 0x0f));
2409f0984d40SFabiano Rosas         gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp);
2410f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2411f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2412f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2413f0984d40SFabiano Rosas         break;
2414f0984d40SFabiano Rosas     case 0x018: case 0x118: case 0x218: case 0x318:     /* WADD */
2415f0984d40SFabiano Rosas     case 0x418: case 0x518: case 0x618: case 0x718:
2416f0984d40SFabiano Rosas     case 0x818: case 0x918: case 0xa18: case 0xb18:
2417f0984d40SFabiano Rosas     case 0xc18: case 0xd18: case 0xe18: case 0xf18:
2418f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2419f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2420f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
2421f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2422f0984d40SFabiano Rosas         switch ((insn >> 20) & 0xf) {
2423f0984d40SFabiano Rosas         case 0x0:
2424f0984d40SFabiano Rosas             gen_op_iwmmxt_addnb_M0_wRn(rd1);
2425f0984d40SFabiano Rosas             break;
2426f0984d40SFabiano Rosas         case 0x1:
2427f0984d40SFabiano Rosas             gen_op_iwmmxt_addub_M0_wRn(rd1);
2428f0984d40SFabiano Rosas             break;
2429f0984d40SFabiano Rosas         case 0x3:
2430f0984d40SFabiano Rosas             gen_op_iwmmxt_addsb_M0_wRn(rd1);
2431f0984d40SFabiano Rosas             break;
2432f0984d40SFabiano Rosas         case 0x4:
2433f0984d40SFabiano Rosas             gen_op_iwmmxt_addnw_M0_wRn(rd1);
2434f0984d40SFabiano Rosas             break;
2435f0984d40SFabiano Rosas         case 0x5:
2436f0984d40SFabiano Rosas             gen_op_iwmmxt_adduw_M0_wRn(rd1);
2437f0984d40SFabiano Rosas             break;
2438f0984d40SFabiano Rosas         case 0x7:
2439f0984d40SFabiano Rosas             gen_op_iwmmxt_addsw_M0_wRn(rd1);
2440f0984d40SFabiano Rosas             break;
2441f0984d40SFabiano Rosas         case 0x8:
2442f0984d40SFabiano Rosas             gen_op_iwmmxt_addnl_M0_wRn(rd1);
2443f0984d40SFabiano Rosas             break;
2444f0984d40SFabiano Rosas         case 0x9:
2445f0984d40SFabiano Rosas             gen_op_iwmmxt_addul_M0_wRn(rd1);
2446f0984d40SFabiano Rosas             break;
2447f0984d40SFabiano Rosas         case 0xb:
2448f0984d40SFabiano Rosas             gen_op_iwmmxt_addsl_M0_wRn(rd1);
2449f0984d40SFabiano Rosas             break;
2450f0984d40SFabiano Rosas         default:
2451f0984d40SFabiano Rosas             return 1;
2452f0984d40SFabiano Rosas         }
2453f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2454f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2455f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2456f0984d40SFabiano Rosas         break;
2457f0984d40SFabiano Rosas     case 0x008: case 0x108: case 0x208: case 0x308:     /* WPACK */
2458f0984d40SFabiano Rosas     case 0x408: case 0x508: case 0x608: case 0x708:
2459f0984d40SFabiano Rosas     case 0x808: case 0x908: case 0xa08: case 0xb08:
2460f0984d40SFabiano Rosas     case 0xc08: case 0xd08: case 0xe08: case 0xf08:
2461f0984d40SFabiano Rosas         if (!(insn & (1 << 20)) || ((insn >> 22) & 3) == 0)
2462f0984d40SFabiano Rosas             return 1;
2463f0984d40SFabiano Rosas         wrd = (insn >> 12) & 0xf;
2464f0984d40SFabiano Rosas         rd0 = (insn >> 16) & 0xf;
2465f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
2466f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(rd0);
2467f0984d40SFabiano Rosas         switch ((insn >> 22) & 3) {
2468f0984d40SFabiano Rosas         case 1:
2469f0984d40SFabiano Rosas             if (insn & (1 << 21))
2470f0984d40SFabiano Rosas                 gen_op_iwmmxt_packsw_M0_wRn(rd1);
2471f0984d40SFabiano Rosas             else
2472f0984d40SFabiano Rosas                 gen_op_iwmmxt_packuw_M0_wRn(rd1);
2473f0984d40SFabiano Rosas             break;
2474f0984d40SFabiano Rosas         case 2:
2475f0984d40SFabiano Rosas             if (insn & (1 << 21))
2476f0984d40SFabiano Rosas                 gen_op_iwmmxt_packsl_M0_wRn(rd1);
2477f0984d40SFabiano Rosas             else
2478f0984d40SFabiano Rosas                 gen_op_iwmmxt_packul_M0_wRn(rd1);
2479f0984d40SFabiano Rosas             break;
2480f0984d40SFabiano Rosas         case 3:
2481f0984d40SFabiano Rosas             if (insn & (1 << 21))
2482f0984d40SFabiano Rosas                 gen_op_iwmmxt_packsq_M0_wRn(rd1);
2483f0984d40SFabiano Rosas             else
2484f0984d40SFabiano Rosas                 gen_op_iwmmxt_packuq_M0_wRn(rd1);
2485f0984d40SFabiano Rosas             break;
2486f0984d40SFabiano Rosas         }
2487f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2488f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2489f0984d40SFabiano Rosas         gen_op_iwmmxt_set_cup();
2490f0984d40SFabiano Rosas         break;
2491f0984d40SFabiano Rosas     case 0x201: case 0x203: case 0x205: case 0x207:
2492f0984d40SFabiano Rosas     case 0x209: case 0x20b: case 0x20d: case 0x20f:
2493f0984d40SFabiano Rosas     case 0x211: case 0x213: case 0x215: case 0x217:
2494f0984d40SFabiano Rosas     case 0x219: case 0x21b: case 0x21d: case 0x21f:
2495f0984d40SFabiano Rosas         wrd = (insn >> 5) & 0xf;
2496f0984d40SFabiano Rosas         rd0 = (insn >> 12) & 0xf;
2497f0984d40SFabiano Rosas         rd1 = (insn >> 0) & 0xf;
2498f0984d40SFabiano Rosas         if (rd0 == 0xf || rd1 == 0xf)
2499f0984d40SFabiano Rosas             return 1;
2500f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_M0_wRn(wrd);
2501f0984d40SFabiano Rosas         tmp = load_reg(s, rd0);
2502f0984d40SFabiano Rosas         tmp2 = load_reg(s, rd1);
2503f0984d40SFabiano Rosas         switch ((insn >> 16) & 0xf) {
2504f0984d40SFabiano Rosas         case 0x0:                                       /* TMIA */
2505f0984d40SFabiano Rosas             gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
2506f0984d40SFabiano Rosas             break;
2507f0984d40SFabiano Rosas         case 0x8:                                       /* TMIAPH */
2508f0984d40SFabiano Rosas             gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
2509f0984d40SFabiano Rosas             break;
2510f0984d40SFabiano Rosas         case 0xc: case 0xd: case 0xe: case 0xf:                 /* TMIAxy */
2511f0984d40SFabiano Rosas             if (insn & (1 << 16))
2512f0984d40SFabiano Rosas                 tcg_gen_shri_i32(tmp, tmp, 16);
2513f0984d40SFabiano Rosas             if (insn & (1 << 17))
2514f0984d40SFabiano Rosas                 tcg_gen_shri_i32(tmp2, tmp2, 16);
2515f0984d40SFabiano Rosas             gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
2516f0984d40SFabiano Rosas             break;
2517f0984d40SFabiano Rosas         default:
2518f0984d40SFabiano Rosas             tcg_temp_free_i32(tmp2);
2519f0984d40SFabiano Rosas             tcg_temp_free_i32(tmp);
2520f0984d40SFabiano Rosas             return 1;
2521f0984d40SFabiano Rosas         }
2522f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp2);
2523f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
2524f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(wrd);
2525f0984d40SFabiano Rosas         gen_op_iwmmxt_set_mup();
2526f0984d40SFabiano Rosas         break;
2527f0984d40SFabiano Rosas     default:
2528f0984d40SFabiano Rosas         return 1;
2529f0984d40SFabiano Rosas     }
2530f0984d40SFabiano Rosas 
2531f0984d40SFabiano Rosas     return 0;
2532f0984d40SFabiano Rosas }
2533f0984d40SFabiano Rosas 
2534f0984d40SFabiano Rosas /* Disassemble an XScale DSP instruction.  Returns nonzero if an error occurred
2535f0984d40SFabiano Rosas    (ie. an undefined instruction).  */
2536f0984d40SFabiano Rosas static int disas_dsp_insn(DisasContext *s, uint32_t insn)
2537f0984d40SFabiano Rosas {
2538f0984d40SFabiano Rosas     int acc, rd0, rd1, rdhi, rdlo;
2539f0984d40SFabiano Rosas     TCGv_i32 tmp, tmp2;
2540f0984d40SFabiano Rosas 
2541f0984d40SFabiano Rosas     if ((insn & 0x0ff00f10) == 0x0e200010) {
2542f0984d40SFabiano Rosas         /* Multiply with Internal Accumulate Format */
2543f0984d40SFabiano Rosas         rd0 = (insn >> 12) & 0xf;
2544f0984d40SFabiano Rosas         rd1 = insn & 0xf;
2545f0984d40SFabiano Rosas         acc = (insn >> 5) & 7;
2546f0984d40SFabiano Rosas 
2547f0984d40SFabiano Rosas         if (acc != 0)
2548f0984d40SFabiano Rosas             return 1;
2549f0984d40SFabiano Rosas 
2550f0984d40SFabiano Rosas         tmp = load_reg(s, rd0);
2551f0984d40SFabiano Rosas         tmp2 = load_reg(s, rd1);
2552f0984d40SFabiano Rosas         switch ((insn >> 16) & 0xf) {
2553f0984d40SFabiano Rosas         case 0x0:                                       /* MIA */
2554f0984d40SFabiano Rosas             gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
2555f0984d40SFabiano Rosas             break;
2556f0984d40SFabiano Rosas         case 0x8:                                       /* MIAPH */
2557f0984d40SFabiano Rosas             gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
2558f0984d40SFabiano Rosas             break;
2559f0984d40SFabiano Rosas         case 0xc:                                       /* MIABB */
2560f0984d40SFabiano Rosas         case 0xd:                                       /* MIABT */
2561f0984d40SFabiano Rosas         case 0xe:                                       /* MIATB */
2562f0984d40SFabiano Rosas         case 0xf:                                       /* MIATT */
2563f0984d40SFabiano Rosas             if (insn & (1 << 16))
2564f0984d40SFabiano Rosas                 tcg_gen_shri_i32(tmp, tmp, 16);
2565f0984d40SFabiano Rosas             if (insn & (1 << 17))
2566f0984d40SFabiano Rosas                 tcg_gen_shri_i32(tmp2, tmp2, 16);
2567f0984d40SFabiano Rosas             gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
2568f0984d40SFabiano Rosas             break;
2569f0984d40SFabiano Rosas         default:
2570f0984d40SFabiano Rosas             return 1;
2571f0984d40SFabiano Rosas         }
2572f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp2);
2573f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
2574f0984d40SFabiano Rosas 
2575f0984d40SFabiano Rosas         gen_op_iwmmxt_movq_wRn_M0(acc);
2576f0984d40SFabiano Rosas         return 0;
2577f0984d40SFabiano Rosas     }
2578f0984d40SFabiano Rosas 
2579f0984d40SFabiano Rosas     if ((insn & 0x0fe00ff8) == 0x0c400000) {
2580f0984d40SFabiano Rosas         /* Internal Accumulator Access Format */
2581f0984d40SFabiano Rosas         rdhi = (insn >> 16) & 0xf;
2582f0984d40SFabiano Rosas         rdlo = (insn >> 12) & 0xf;
2583f0984d40SFabiano Rosas         acc = insn & 7;
2584f0984d40SFabiano Rosas 
2585f0984d40SFabiano Rosas         if (acc != 0)
2586f0984d40SFabiano Rosas             return 1;
2587f0984d40SFabiano Rosas 
2588f0984d40SFabiano Rosas         if (insn & ARM_CP_RW_BIT) {                     /* MRA */
2589f0984d40SFabiano Rosas             iwmmxt_load_reg(cpu_V0, acc);
2590f0984d40SFabiano Rosas             tcg_gen_extrl_i64_i32(cpu_R[rdlo], cpu_V0);
2591f0984d40SFabiano Rosas             tcg_gen_extrh_i64_i32(cpu_R[rdhi], cpu_V0);
2592f0984d40SFabiano Rosas             tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1);
2593f0984d40SFabiano Rosas         } else {                                        /* MAR */
2594f0984d40SFabiano Rosas             tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
2595f0984d40SFabiano Rosas             iwmmxt_store_reg(cpu_V0, acc);
2596f0984d40SFabiano Rosas         }
2597f0984d40SFabiano Rosas         return 0;
2598f0984d40SFabiano Rosas     }
2599f0984d40SFabiano Rosas 
2600f0984d40SFabiano Rosas     return 1;
2601f0984d40SFabiano Rosas }
2602f0984d40SFabiano Rosas 
2603f0984d40SFabiano Rosas static void gen_goto_ptr(void)
2604f0984d40SFabiano Rosas {
2605f0984d40SFabiano Rosas     tcg_gen_lookup_and_goto_ptr();
2606f0984d40SFabiano Rosas }
2607f0984d40SFabiano Rosas 
2608f0984d40SFabiano Rosas /* This will end the TB but doesn't guarantee we'll return to
2609f0984d40SFabiano Rosas  * cpu_loop_exec. Any live exit_requests will be processed as we
2610f0984d40SFabiano Rosas  * enter the next TB.
2611f0984d40SFabiano Rosas  */
2612f0984d40SFabiano Rosas static void gen_goto_tb(DisasContext *s, int n, target_long diff)
2613f0984d40SFabiano Rosas {
2614f0984d40SFabiano Rosas     if (translator_use_goto_tb(&s->base, s->pc_curr + diff)) {
2615f0984d40SFabiano Rosas         /*
2616f0984d40SFabiano Rosas          * For pcrel, the pc must always be up-to-date on entry to
2617f0984d40SFabiano Rosas          * the linked TB, so that it can use simple additions for all
2618f0984d40SFabiano Rosas          * further adjustments.  For !pcrel, the linked TB is compiled
2619f0984d40SFabiano Rosas          * to know its full virtual address, so we can delay the
2620f0984d40SFabiano Rosas          * update to pc to the unlinked path.  A long chain of links
2621f0984d40SFabiano Rosas          * can thus avoid many updates to the PC.
2622f0984d40SFabiano Rosas          */
262303a648c4SAnton Johansson         if (tb_cflags(s->base.tb) & CF_PCREL) {
2624f0984d40SFabiano Rosas             gen_update_pc(s, diff);
2625f0984d40SFabiano Rosas             tcg_gen_goto_tb(n);
2626f0984d40SFabiano Rosas         } else {
2627f0984d40SFabiano Rosas             tcg_gen_goto_tb(n);
2628f0984d40SFabiano Rosas             gen_update_pc(s, diff);
2629f0984d40SFabiano Rosas         }
2630f0984d40SFabiano Rosas         tcg_gen_exit_tb(s->base.tb, n);
2631f0984d40SFabiano Rosas     } else {
2632f0984d40SFabiano Rosas         gen_update_pc(s, diff);
2633f0984d40SFabiano Rosas         gen_goto_ptr();
2634f0984d40SFabiano Rosas     }
2635f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_NORETURN;
2636f0984d40SFabiano Rosas }
2637f0984d40SFabiano Rosas 
2638f0984d40SFabiano Rosas /* Jump, specifying which TB number to use if we gen_goto_tb() */
2639f0984d40SFabiano Rosas static void gen_jmp_tb(DisasContext *s, target_long diff, int tbno)
2640f0984d40SFabiano Rosas {
2641f0984d40SFabiano Rosas     if (unlikely(s->ss_active)) {
2642f0984d40SFabiano Rosas         /* An indirect jump so that we still trigger the debug exception.  */
2643f0984d40SFabiano Rosas         gen_update_pc(s, diff);
2644f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_JUMP;
2645f0984d40SFabiano Rosas         return;
2646f0984d40SFabiano Rosas     }
2647f0984d40SFabiano Rosas     switch (s->base.is_jmp) {
2648f0984d40SFabiano Rosas     case DISAS_NEXT:
2649f0984d40SFabiano Rosas     case DISAS_TOO_MANY:
2650f0984d40SFabiano Rosas     case DISAS_NORETURN:
2651f0984d40SFabiano Rosas         /*
2652f0984d40SFabiano Rosas          * The normal case: just go to the destination TB.
2653f0984d40SFabiano Rosas          * NB: NORETURN happens if we generate code like
2654f0984d40SFabiano Rosas          *    gen_brcondi(l);
2655f0984d40SFabiano Rosas          *    gen_jmp();
2656f0984d40SFabiano Rosas          *    gen_set_label(l);
2657f0984d40SFabiano Rosas          *    gen_jmp();
2658f0984d40SFabiano Rosas          * on the second call to gen_jmp().
2659f0984d40SFabiano Rosas          */
2660f0984d40SFabiano Rosas         gen_goto_tb(s, tbno, diff);
2661f0984d40SFabiano Rosas         break;
2662f0984d40SFabiano Rosas     case DISAS_UPDATE_NOCHAIN:
2663f0984d40SFabiano Rosas     case DISAS_UPDATE_EXIT:
2664f0984d40SFabiano Rosas         /*
2665f0984d40SFabiano Rosas          * We already decided we're leaving the TB for some other reason.
2666f0984d40SFabiano Rosas          * Avoid using goto_tb so we really do exit back to the main loop
2667f0984d40SFabiano Rosas          * and don't chain to another TB.
2668f0984d40SFabiano Rosas          */
2669f0984d40SFabiano Rosas         gen_update_pc(s, diff);
2670f0984d40SFabiano Rosas         gen_goto_ptr();
2671f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_NORETURN;
2672f0984d40SFabiano Rosas         break;
2673f0984d40SFabiano Rosas     default:
2674f0984d40SFabiano Rosas         /*
2675f0984d40SFabiano Rosas          * We shouldn't be emitting code for a jump and also have
2676f0984d40SFabiano Rosas          * is_jmp set to one of the special cases like DISAS_SWI.
2677f0984d40SFabiano Rosas          */
2678f0984d40SFabiano Rosas         g_assert_not_reached();
2679f0984d40SFabiano Rosas     }
2680f0984d40SFabiano Rosas }
2681f0984d40SFabiano Rosas 
2682f0984d40SFabiano Rosas static inline void gen_jmp(DisasContext *s, target_long diff)
2683f0984d40SFabiano Rosas {
2684f0984d40SFabiano Rosas     gen_jmp_tb(s, diff, 0);
2685f0984d40SFabiano Rosas }
2686f0984d40SFabiano Rosas 
2687f0984d40SFabiano Rosas static inline void gen_mulxy(TCGv_i32 t0, TCGv_i32 t1, int x, int y)
2688f0984d40SFabiano Rosas {
2689f0984d40SFabiano Rosas     if (x)
2690f0984d40SFabiano Rosas         tcg_gen_sari_i32(t0, t0, 16);
2691f0984d40SFabiano Rosas     else
2692f0984d40SFabiano Rosas         gen_sxth(t0);
2693f0984d40SFabiano Rosas     if (y)
2694f0984d40SFabiano Rosas         tcg_gen_sari_i32(t1, t1, 16);
2695f0984d40SFabiano Rosas     else
2696f0984d40SFabiano Rosas         gen_sxth(t1);
2697f0984d40SFabiano Rosas     tcg_gen_mul_i32(t0, t0, t1);
2698f0984d40SFabiano Rosas }
2699f0984d40SFabiano Rosas 
2700f0984d40SFabiano Rosas /* Return the mask of PSR bits set by a MSR instruction.  */
2701f0984d40SFabiano Rosas static uint32_t msr_mask(DisasContext *s, int flags, int spsr)
2702f0984d40SFabiano Rosas {
2703f0984d40SFabiano Rosas     uint32_t mask = 0;
2704f0984d40SFabiano Rosas 
2705f0984d40SFabiano Rosas     if (flags & (1 << 0)) {
2706f0984d40SFabiano Rosas         mask |= 0xff;
2707f0984d40SFabiano Rosas     }
2708f0984d40SFabiano Rosas     if (flags & (1 << 1)) {
2709f0984d40SFabiano Rosas         mask |= 0xff00;
2710f0984d40SFabiano Rosas     }
2711f0984d40SFabiano Rosas     if (flags & (1 << 2)) {
2712f0984d40SFabiano Rosas         mask |= 0xff0000;
2713f0984d40SFabiano Rosas     }
2714f0984d40SFabiano Rosas     if (flags & (1 << 3)) {
2715f0984d40SFabiano Rosas         mask |= 0xff000000;
2716f0984d40SFabiano Rosas     }
2717f0984d40SFabiano Rosas 
2718f0984d40SFabiano Rosas     /* Mask out undefined and reserved bits.  */
2719f0984d40SFabiano Rosas     mask &= aarch32_cpsr_valid_mask(s->features, s->isar);
2720f0984d40SFabiano Rosas 
2721f0984d40SFabiano Rosas     /* Mask out execution state.  */
2722f0984d40SFabiano Rosas     if (!spsr) {
2723f0984d40SFabiano Rosas         mask &= ~CPSR_EXEC;
2724f0984d40SFabiano Rosas     }
2725f0984d40SFabiano Rosas 
2726f0984d40SFabiano Rosas     /* Mask out privileged bits.  */
2727f0984d40SFabiano Rosas     if (IS_USER(s)) {
2728f0984d40SFabiano Rosas         mask &= CPSR_USER;
2729f0984d40SFabiano Rosas     }
2730f0984d40SFabiano Rosas     return mask;
2731f0984d40SFabiano Rosas }
2732f0984d40SFabiano Rosas 
2733f0984d40SFabiano Rosas /* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
2734f0984d40SFabiano Rosas static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv_i32 t0)
2735f0984d40SFabiano Rosas {
2736f0984d40SFabiano Rosas     TCGv_i32 tmp;
2737f0984d40SFabiano Rosas     if (spsr) {
2738f0984d40SFabiano Rosas         /* ??? This is also undefined in system mode.  */
2739f0984d40SFabiano Rosas         if (IS_USER(s))
2740f0984d40SFabiano Rosas             return 1;
2741f0984d40SFabiano Rosas 
2742f0984d40SFabiano Rosas         tmp = load_cpu_field(spsr);
2743f0984d40SFabiano Rosas         tcg_gen_andi_i32(tmp, tmp, ~mask);
2744f0984d40SFabiano Rosas         tcg_gen_andi_i32(t0, t0, mask);
2745f0984d40SFabiano Rosas         tcg_gen_or_i32(tmp, tmp, t0);
2746f0984d40SFabiano Rosas         store_cpu_field(tmp, spsr);
2747f0984d40SFabiano Rosas     } else {
2748f0984d40SFabiano Rosas         gen_set_cpsr(t0, mask);
2749f0984d40SFabiano Rosas     }
2750f0984d40SFabiano Rosas     tcg_temp_free_i32(t0);
2751f0984d40SFabiano Rosas     gen_lookup_tb(s);
2752f0984d40SFabiano Rosas     return 0;
2753f0984d40SFabiano Rosas }
2754f0984d40SFabiano Rosas 
2755f0984d40SFabiano Rosas /* Returns nonzero if access to the PSR is not permitted.  */
2756f0984d40SFabiano Rosas static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val)
2757f0984d40SFabiano Rosas {
2758f0984d40SFabiano Rosas     TCGv_i32 tmp;
2759f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
2760f0984d40SFabiano Rosas     tcg_gen_movi_i32(tmp, val);
2761f0984d40SFabiano Rosas     return gen_set_psr(s, mask, spsr, tmp);
2762f0984d40SFabiano Rosas }
2763f0984d40SFabiano Rosas 
2764f0984d40SFabiano Rosas static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
2765f0984d40SFabiano Rosas                                      int *tgtmode, int *regno)
2766f0984d40SFabiano Rosas {
2767f0984d40SFabiano Rosas     /* Decode the r and sysm fields of MSR/MRS banked accesses into
2768f0984d40SFabiano Rosas      * the target mode and register number, and identify the various
2769f0984d40SFabiano Rosas      * unpredictable cases.
2770f0984d40SFabiano Rosas      * MSR (banked) and MRS (banked) are CONSTRAINED UNPREDICTABLE if:
2771f0984d40SFabiano Rosas      *  + executed in user mode
2772f0984d40SFabiano Rosas      *  + using R15 as the src/dest register
2773f0984d40SFabiano Rosas      *  + accessing an unimplemented register
2774f0984d40SFabiano Rosas      *  + accessing a register that's inaccessible at current PL/security state*
2775f0984d40SFabiano Rosas      *  + accessing a register that you could access with a different insn
2776f0984d40SFabiano Rosas      * We choose to UNDEF in all these cases.
2777f0984d40SFabiano Rosas      * Since we don't know which of the various AArch32 modes we are in
2778f0984d40SFabiano Rosas      * we have to defer some checks to runtime.
2779f0984d40SFabiano Rosas      * Accesses to Monitor mode registers from Secure EL1 (which implies
2780f0984d40SFabiano Rosas      * that EL3 is AArch64) must trap to EL3.
2781f0984d40SFabiano Rosas      *
2782f0984d40SFabiano Rosas      * If the access checks fail this function will emit code to take
2783f0984d40SFabiano Rosas      * an exception and return false. Otherwise it will return true,
2784f0984d40SFabiano Rosas      * and set *tgtmode and *regno appropriately.
2785f0984d40SFabiano Rosas      */
2786f0984d40SFabiano Rosas     /* These instructions are present only in ARMv8, or in ARMv7 with the
2787f0984d40SFabiano Rosas      * Virtualization Extensions.
2788f0984d40SFabiano Rosas      */
2789f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V8) &&
2790f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_EL2)) {
2791f0984d40SFabiano Rosas         goto undef;
2792f0984d40SFabiano Rosas     }
2793f0984d40SFabiano Rosas 
2794f0984d40SFabiano Rosas     if (IS_USER(s) || rn == 15) {
2795f0984d40SFabiano Rosas         goto undef;
2796f0984d40SFabiano Rosas     }
2797f0984d40SFabiano Rosas 
2798f0984d40SFabiano Rosas     /* The table in the v8 ARM ARM section F5.2.3 describes the encoding
2799f0984d40SFabiano Rosas      * of registers into (r, sysm).
2800f0984d40SFabiano Rosas      */
2801f0984d40SFabiano Rosas     if (r) {
2802f0984d40SFabiano Rosas         /* SPSRs for other modes */
2803f0984d40SFabiano Rosas         switch (sysm) {
2804f0984d40SFabiano Rosas         case 0xe: /* SPSR_fiq */
2805f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_FIQ;
2806f0984d40SFabiano Rosas             break;
2807f0984d40SFabiano Rosas         case 0x10: /* SPSR_irq */
2808f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_IRQ;
2809f0984d40SFabiano Rosas             break;
2810f0984d40SFabiano Rosas         case 0x12: /* SPSR_svc */
2811f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_SVC;
2812f0984d40SFabiano Rosas             break;
2813f0984d40SFabiano Rosas         case 0x14: /* SPSR_abt */
2814f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_ABT;
2815f0984d40SFabiano Rosas             break;
2816f0984d40SFabiano Rosas         case 0x16: /* SPSR_und */
2817f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_UND;
2818f0984d40SFabiano Rosas             break;
2819f0984d40SFabiano Rosas         case 0x1c: /* SPSR_mon */
2820f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_MON;
2821f0984d40SFabiano Rosas             break;
2822f0984d40SFabiano Rosas         case 0x1e: /* SPSR_hyp */
2823f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_HYP;
2824f0984d40SFabiano Rosas             break;
2825f0984d40SFabiano Rosas         default: /* unallocated */
2826f0984d40SFabiano Rosas             goto undef;
2827f0984d40SFabiano Rosas         }
2828f0984d40SFabiano Rosas         /* We arbitrarily assign SPSR a register number of 16. */
2829f0984d40SFabiano Rosas         *regno = 16;
2830f0984d40SFabiano Rosas     } else {
2831f0984d40SFabiano Rosas         /* general purpose registers for other modes */
2832f0984d40SFabiano Rosas         switch (sysm) {
2833f0984d40SFabiano Rosas         case 0x0 ... 0x6:   /* 0b00xxx : r8_usr ... r14_usr */
2834f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_USR;
2835f0984d40SFabiano Rosas             *regno = sysm + 8;
2836f0984d40SFabiano Rosas             break;
2837f0984d40SFabiano Rosas         case 0x8 ... 0xe:   /* 0b01xxx : r8_fiq ... r14_fiq */
2838f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_FIQ;
2839f0984d40SFabiano Rosas             *regno = sysm;
2840f0984d40SFabiano Rosas             break;
2841f0984d40SFabiano Rosas         case 0x10 ... 0x11: /* 0b1000x : r14_irq, r13_irq */
2842f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_IRQ;
2843f0984d40SFabiano Rosas             *regno = sysm & 1 ? 13 : 14;
2844f0984d40SFabiano Rosas             break;
2845f0984d40SFabiano Rosas         case 0x12 ... 0x13: /* 0b1001x : r14_svc, r13_svc */
2846f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_SVC;
2847f0984d40SFabiano Rosas             *regno = sysm & 1 ? 13 : 14;
2848f0984d40SFabiano Rosas             break;
2849f0984d40SFabiano Rosas         case 0x14 ... 0x15: /* 0b1010x : r14_abt, r13_abt */
2850f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_ABT;
2851f0984d40SFabiano Rosas             *regno = sysm & 1 ? 13 : 14;
2852f0984d40SFabiano Rosas             break;
2853f0984d40SFabiano Rosas         case 0x16 ... 0x17: /* 0b1011x : r14_und, r13_und */
2854f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_UND;
2855f0984d40SFabiano Rosas             *regno = sysm & 1 ? 13 : 14;
2856f0984d40SFabiano Rosas             break;
2857f0984d40SFabiano Rosas         case 0x1c ... 0x1d: /* 0b1110x : r14_mon, r13_mon */
2858f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_MON;
2859f0984d40SFabiano Rosas             *regno = sysm & 1 ? 13 : 14;
2860f0984d40SFabiano Rosas             break;
2861f0984d40SFabiano Rosas         case 0x1e ... 0x1f: /* 0b1111x : elr_hyp, r13_hyp */
2862f0984d40SFabiano Rosas             *tgtmode = ARM_CPU_MODE_HYP;
2863f0984d40SFabiano Rosas             /* Arbitrarily pick 17 for ELR_Hyp (which is not a banked LR!) */
2864f0984d40SFabiano Rosas             *regno = sysm & 1 ? 13 : 17;
2865f0984d40SFabiano Rosas             break;
2866f0984d40SFabiano Rosas         default: /* unallocated */
2867f0984d40SFabiano Rosas             goto undef;
2868f0984d40SFabiano Rosas         }
2869f0984d40SFabiano Rosas     }
2870f0984d40SFabiano Rosas 
2871f0984d40SFabiano Rosas     /* Catch the 'accessing inaccessible register' cases we can detect
2872f0984d40SFabiano Rosas      * at translate time.
2873f0984d40SFabiano Rosas      */
2874f0984d40SFabiano Rosas     switch (*tgtmode) {
2875f0984d40SFabiano Rosas     case ARM_CPU_MODE_MON:
2876f0984d40SFabiano Rosas         if (!arm_dc_feature(s, ARM_FEATURE_EL3) || s->ns) {
2877f0984d40SFabiano Rosas             goto undef;
2878f0984d40SFabiano Rosas         }
2879f0984d40SFabiano Rosas         if (s->current_el == 1) {
2880f0984d40SFabiano Rosas             /* If we're in Secure EL1 (which implies that EL3 is AArch64)
2881f0984d40SFabiano Rosas              * then accesses to Mon registers trap to Secure EL2, if it exists,
2882f0984d40SFabiano Rosas              * otherwise EL3.
2883f0984d40SFabiano Rosas              */
2884f0984d40SFabiano Rosas             TCGv_i32 tcg_el;
2885f0984d40SFabiano Rosas 
2886f0984d40SFabiano Rosas             if (arm_dc_feature(s, ARM_FEATURE_AARCH64) &&
2887f0984d40SFabiano Rosas                 dc_isar_feature(aa64_sel2, s)) {
2888f0984d40SFabiano Rosas                 /* Target EL is EL<3 minus SCR_EL3.EEL2> */
2889f0984d40SFabiano Rosas                 tcg_el = load_cpu_field(cp15.scr_el3);
2890f0984d40SFabiano Rosas                 tcg_gen_sextract_i32(tcg_el, tcg_el, ctz32(SCR_EEL2), 1);
2891f0984d40SFabiano Rosas                 tcg_gen_addi_i32(tcg_el, tcg_el, 3);
2892f0984d40SFabiano Rosas             } else {
2893f0984d40SFabiano Rosas                 tcg_el = tcg_constant_i32(3);
2894f0984d40SFabiano Rosas             }
2895f0984d40SFabiano Rosas 
2896f0984d40SFabiano Rosas             gen_exception_insn_el_v(s, 0, EXCP_UDEF,
2897f0984d40SFabiano Rosas                                     syn_uncategorized(), tcg_el);
2898f0984d40SFabiano Rosas             tcg_temp_free_i32(tcg_el);
2899f0984d40SFabiano Rosas             return false;
2900f0984d40SFabiano Rosas         }
2901f0984d40SFabiano Rosas         break;
2902f0984d40SFabiano Rosas     case ARM_CPU_MODE_HYP:
2903f0984d40SFabiano Rosas         /*
2904f0984d40SFabiano Rosas          * SPSR_hyp and r13_hyp can only be accessed from Monitor mode
2905f0984d40SFabiano Rosas          * (and so we can forbid accesses from EL2 or below). elr_hyp
2906f0984d40SFabiano Rosas          * can be accessed also from Hyp mode, so forbid accesses from
2907f0984d40SFabiano Rosas          * EL0 or EL1.
2908f0984d40SFabiano Rosas          */
2909f0984d40SFabiano Rosas         if (!arm_dc_feature(s, ARM_FEATURE_EL2) || s->current_el < 2 ||
2910f0984d40SFabiano Rosas             (s->current_el < 3 && *regno != 17)) {
2911f0984d40SFabiano Rosas             goto undef;
2912f0984d40SFabiano Rosas         }
2913f0984d40SFabiano Rosas         break;
2914f0984d40SFabiano Rosas     default:
2915f0984d40SFabiano Rosas         break;
2916f0984d40SFabiano Rosas     }
2917f0984d40SFabiano Rosas 
2918f0984d40SFabiano Rosas     return true;
2919f0984d40SFabiano Rosas 
2920f0984d40SFabiano Rosas undef:
2921f0984d40SFabiano Rosas     /* If we get here then some access check did not pass */
2922f0984d40SFabiano Rosas     gen_exception_insn(s, 0, EXCP_UDEF, syn_uncategorized());
2923f0984d40SFabiano Rosas     return false;
2924f0984d40SFabiano Rosas }
2925f0984d40SFabiano Rosas 
2926f0984d40SFabiano Rosas static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
2927f0984d40SFabiano Rosas {
2928f0984d40SFabiano Rosas     TCGv_i32 tcg_reg;
2929f0984d40SFabiano Rosas     int tgtmode = 0, regno = 0;
2930f0984d40SFabiano Rosas 
2931f0984d40SFabiano Rosas     if (!msr_banked_access_decode(s, r, sysm, rn, &tgtmode, &regno)) {
2932f0984d40SFabiano Rosas         return;
2933f0984d40SFabiano Rosas     }
2934f0984d40SFabiano Rosas 
2935f0984d40SFabiano Rosas     /* Sync state because msr_banked() can raise exceptions */
2936f0984d40SFabiano Rosas     gen_set_condexec(s);
2937f0984d40SFabiano Rosas     gen_update_pc(s, 0);
2938f0984d40SFabiano Rosas     tcg_reg = load_reg(s, rn);
2939f0984d40SFabiano Rosas     gen_helper_msr_banked(cpu_env, tcg_reg,
2940f0984d40SFabiano Rosas                           tcg_constant_i32(tgtmode),
2941f0984d40SFabiano Rosas                           tcg_constant_i32(regno));
2942f0984d40SFabiano Rosas     tcg_temp_free_i32(tcg_reg);
2943f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_UPDATE_EXIT;
2944f0984d40SFabiano Rosas }
2945f0984d40SFabiano Rosas 
2946f0984d40SFabiano Rosas static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
2947f0984d40SFabiano Rosas {
2948f0984d40SFabiano Rosas     TCGv_i32 tcg_reg;
2949f0984d40SFabiano Rosas     int tgtmode = 0, regno = 0;
2950f0984d40SFabiano Rosas 
2951f0984d40SFabiano Rosas     if (!msr_banked_access_decode(s, r, sysm, rn, &tgtmode, &regno)) {
2952f0984d40SFabiano Rosas         return;
2953f0984d40SFabiano Rosas     }
2954f0984d40SFabiano Rosas 
2955f0984d40SFabiano Rosas     /* Sync state because mrs_banked() can raise exceptions */
2956f0984d40SFabiano Rosas     gen_set_condexec(s);
2957f0984d40SFabiano Rosas     gen_update_pc(s, 0);
2958f0984d40SFabiano Rosas     tcg_reg = tcg_temp_new_i32();
2959f0984d40SFabiano Rosas     gen_helper_mrs_banked(tcg_reg, cpu_env,
2960f0984d40SFabiano Rosas                           tcg_constant_i32(tgtmode),
2961f0984d40SFabiano Rosas                           tcg_constant_i32(regno));
2962f0984d40SFabiano Rosas     store_reg(s, rn, tcg_reg);
2963f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_UPDATE_EXIT;
2964f0984d40SFabiano Rosas }
2965f0984d40SFabiano Rosas 
2966f0984d40SFabiano Rosas /* Store value to PC as for an exception return (ie don't
2967f0984d40SFabiano Rosas  * mask bits). The subsequent call to gen_helper_cpsr_write_eret()
2968f0984d40SFabiano Rosas  * will do the masking based on the new value of the Thumb bit.
2969f0984d40SFabiano Rosas  */
2970f0984d40SFabiano Rosas static void store_pc_exc_ret(DisasContext *s, TCGv_i32 pc)
2971f0984d40SFabiano Rosas {
2972f0984d40SFabiano Rosas     tcg_gen_mov_i32(cpu_R[15], pc);
2973f0984d40SFabiano Rosas     tcg_temp_free_i32(pc);
2974f0984d40SFabiano Rosas }
2975f0984d40SFabiano Rosas 
2976f0984d40SFabiano Rosas /* Generate a v6 exception return.  Marks both values as dead.  */
2977f0984d40SFabiano Rosas static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
2978f0984d40SFabiano Rosas {
2979f0984d40SFabiano Rosas     store_pc_exc_ret(s, pc);
2980f0984d40SFabiano Rosas     /* The cpsr_write_eret helper will mask the low bits of PC
2981f0984d40SFabiano Rosas      * appropriately depending on the new Thumb bit, so it must
2982f0984d40SFabiano Rosas      * be called after storing the new PC.
2983f0984d40SFabiano Rosas      */
2984f0984d40SFabiano Rosas     if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
2985f0984d40SFabiano Rosas         gen_io_start();
2986f0984d40SFabiano Rosas     }
2987f0984d40SFabiano Rosas     gen_helper_cpsr_write_eret(cpu_env, cpsr);
2988f0984d40SFabiano Rosas     tcg_temp_free_i32(cpsr);
2989f0984d40SFabiano Rosas     /* Must exit loop to check un-masked IRQs */
2990f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_EXIT;
2991f0984d40SFabiano Rosas }
2992f0984d40SFabiano Rosas 
2993f0984d40SFabiano Rosas /* Generate an old-style exception return. Marks pc as dead. */
2994f0984d40SFabiano Rosas static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
2995f0984d40SFabiano Rosas {
2996f0984d40SFabiano Rosas     gen_rfe(s, pc, load_cpu_field(spsr));
2997f0984d40SFabiano Rosas }
2998f0984d40SFabiano Rosas 
2999f0984d40SFabiano Rosas static void gen_gvec_fn3_qc(uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs,
3000f0984d40SFabiano Rosas                             uint32_t opr_sz, uint32_t max_sz,
3001f0984d40SFabiano Rosas                             gen_helper_gvec_3_ptr *fn)
3002f0984d40SFabiano Rosas {
3003f0984d40SFabiano Rosas     TCGv_ptr qc_ptr = tcg_temp_new_ptr();
3004f0984d40SFabiano Rosas 
3005f0984d40SFabiano Rosas     tcg_gen_addi_ptr(qc_ptr, cpu_env, offsetof(CPUARMState, vfp.qc));
3006f0984d40SFabiano Rosas     tcg_gen_gvec_3_ptr(rd_ofs, rn_ofs, rm_ofs, qc_ptr,
3007f0984d40SFabiano Rosas                        opr_sz, max_sz, 0, fn);
3008f0984d40SFabiano Rosas     tcg_temp_free_ptr(qc_ptr);
3009f0984d40SFabiano Rosas }
3010f0984d40SFabiano Rosas 
3011f0984d40SFabiano Rosas void gen_gvec_sqrdmlah_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
3012f0984d40SFabiano Rosas                           uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
3013f0984d40SFabiano Rosas {
3014f0984d40SFabiano Rosas     static gen_helper_gvec_3_ptr * const fns[2] = {
3015f0984d40SFabiano Rosas         gen_helper_gvec_qrdmlah_s16, gen_helper_gvec_qrdmlah_s32
3016f0984d40SFabiano Rosas     };
3017f0984d40SFabiano Rosas     tcg_debug_assert(vece >= 1 && vece <= 2);
3018f0984d40SFabiano Rosas     gen_gvec_fn3_qc(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, fns[vece - 1]);
3019f0984d40SFabiano Rosas }
3020f0984d40SFabiano Rosas 
3021f0984d40SFabiano Rosas void gen_gvec_sqrdmlsh_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
3022f0984d40SFabiano Rosas                           uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
3023f0984d40SFabiano Rosas {
3024f0984d40SFabiano Rosas     static gen_helper_gvec_3_ptr * const fns[2] = {
3025f0984d40SFabiano Rosas         gen_helper_gvec_qrdmlsh_s16, gen_helper_gvec_qrdmlsh_s32
3026f0984d40SFabiano Rosas     };
3027f0984d40SFabiano Rosas     tcg_debug_assert(vece >= 1 && vece <= 2);
3028f0984d40SFabiano Rosas     gen_gvec_fn3_qc(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, fns[vece - 1]);
3029f0984d40SFabiano Rosas }
3030f0984d40SFabiano Rosas 
3031f0984d40SFabiano Rosas #define GEN_CMP0(NAME, COND)                                            \
3032f0984d40SFabiano Rosas     static void gen_##NAME##0_i32(TCGv_i32 d, TCGv_i32 a)               \
3033f0984d40SFabiano Rosas     {                                                                   \
3034f0984d40SFabiano Rosas         tcg_gen_setcondi_i32(COND, d, a, 0);                            \
3035f0984d40SFabiano Rosas         tcg_gen_neg_i32(d, d);                                          \
3036f0984d40SFabiano Rosas     }                                                                   \
3037f0984d40SFabiano Rosas     static void gen_##NAME##0_i64(TCGv_i64 d, TCGv_i64 a)               \
3038f0984d40SFabiano Rosas     {                                                                   \
3039f0984d40SFabiano Rosas         tcg_gen_setcondi_i64(COND, d, a, 0);                            \
3040f0984d40SFabiano Rosas         tcg_gen_neg_i64(d, d);                                          \
3041f0984d40SFabiano Rosas     }                                                                   \
3042f0984d40SFabiano Rosas     static void gen_##NAME##0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) \
3043f0984d40SFabiano Rosas     {                                                                   \
3044f0984d40SFabiano Rosas         TCGv_vec zero = tcg_constant_vec_matching(d, vece, 0);          \
3045f0984d40SFabiano Rosas         tcg_gen_cmp_vec(COND, vece, d, a, zero);                        \
3046f0984d40SFabiano Rosas     }                                                                   \
3047f0984d40SFabiano Rosas     void gen_gvec_##NAME##0(unsigned vece, uint32_t d, uint32_t m,      \
3048f0984d40SFabiano Rosas                             uint32_t opr_sz, uint32_t max_sz)           \
3049f0984d40SFabiano Rosas     {                                                                   \
3050f0984d40SFabiano Rosas         const GVecGen2 op[4] = {                                        \
3051f0984d40SFabiano Rosas             { .fno = gen_helper_gvec_##NAME##0_b,                       \
3052f0984d40SFabiano Rosas               .fniv = gen_##NAME##0_vec,                                \
3053f0984d40SFabiano Rosas               .opt_opc = vecop_list_cmp,                                \
3054f0984d40SFabiano Rosas               .vece = MO_8 },                                           \
3055f0984d40SFabiano Rosas             { .fno = gen_helper_gvec_##NAME##0_h,                       \
3056f0984d40SFabiano Rosas               .fniv = gen_##NAME##0_vec,                                \
3057f0984d40SFabiano Rosas               .opt_opc = vecop_list_cmp,                                \
3058f0984d40SFabiano Rosas               .vece = MO_16 },                                          \
3059f0984d40SFabiano Rosas             { .fni4 = gen_##NAME##0_i32,                                \
3060f0984d40SFabiano Rosas               .fniv = gen_##NAME##0_vec,                                \
3061f0984d40SFabiano Rosas               .opt_opc = vecop_list_cmp,                                \
3062f0984d40SFabiano Rosas               .vece = MO_32 },                                          \
3063f0984d40SFabiano Rosas             { .fni8 = gen_##NAME##0_i64,                                \
3064f0984d40SFabiano Rosas               .fniv = gen_##NAME##0_vec,                                \
3065f0984d40SFabiano Rosas               .opt_opc = vecop_list_cmp,                                \
3066f0984d40SFabiano Rosas               .prefer_i64 = TCG_TARGET_REG_BITS == 64,                  \
3067f0984d40SFabiano Rosas               .vece = MO_64 },                                          \
3068f0984d40SFabiano Rosas         };                                                              \
3069f0984d40SFabiano Rosas         tcg_gen_gvec_2(d, m, opr_sz, max_sz, &op[vece]);                \
3070f0984d40SFabiano Rosas     }
3071f0984d40SFabiano Rosas 
3072f0984d40SFabiano Rosas static const TCGOpcode vecop_list_cmp[] = {
3073f0984d40SFabiano Rosas     INDEX_op_cmp_vec, 0
3074f0984d40SFabiano Rosas };
3075f0984d40SFabiano Rosas 
3076f0984d40SFabiano Rosas GEN_CMP0(ceq, TCG_COND_EQ)
3077f0984d40SFabiano Rosas GEN_CMP0(cle, TCG_COND_LE)
3078f0984d40SFabiano Rosas GEN_CMP0(cge, TCG_COND_GE)
3079f0984d40SFabiano Rosas GEN_CMP0(clt, TCG_COND_LT)
3080f0984d40SFabiano Rosas GEN_CMP0(cgt, TCG_COND_GT)
3081f0984d40SFabiano Rosas 
3082f0984d40SFabiano Rosas #undef GEN_CMP0
3083f0984d40SFabiano Rosas 
3084f0984d40SFabiano Rosas static void gen_ssra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3085f0984d40SFabiano Rosas {
3086f0984d40SFabiano Rosas     tcg_gen_vec_sar8i_i64(a, a, shift);
3087f0984d40SFabiano Rosas     tcg_gen_vec_add8_i64(d, d, a);
3088f0984d40SFabiano Rosas }
3089f0984d40SFabiano Rosas 
3090f0984d40SFabiano Rosas static void gen_ssra16_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3091f0984d40SFabiano Rosas {
3092f0984d40SFabiano Rosas     tcg_gen_vec_sar16i_i64(a, a, shift);
3093f0984d40SFabiano Rosas     tcg_gen_vec_add16_i64(d, d, a);
3094f0984d40SFabiano Rosas }
3095f0984d40SFabiano Rosas 
3096f0984d40SFabiano Rosas static void gen_ssra32_i32(TCGv_i32 d, TCGv_i32 a, int32_t shift)
3097f0984d40SFabiano Rosas {
3098f0984d40SFabiano Rosas     tcg_gen_sari_i32(a, a, shift);
3099f0984d40SFabiano Rosas     tcg_gen_add_i32(d, d, a);
3100f0984d40SFabiano Rosas }
3101f0984d40SFabiano Rosas 
3102f0984d40SFabiano Rosas static void gen_ssra64_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3103f0984d40SFabiano Rosas {
3104f0984d40SFabiano Rosas     tcg_gen_sari_i64(a, a, shift);
3105f0984d40SFabiano Rosas     tcg_gen_add_i64(d, d, a);
3106f0984d40SFabiano Rosas }
3107f0984d40SFabiano Rosas 
3108f0984d40SFabiano Rosas static void gen_ssra_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh)
3109f0984d40SFabiano Rosas {
3110f0984d40SFabiano Rosas     tcg_gen_sari_vec(vece, a, a, sh);
3111f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, d, d, a);
3112f0984d40SFabiano Rosas }
3113f0984d40SFabiano Rosas 
3114f0984d40SFabiano Rosas void gen_gvec_ssra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
3115f0984d40SFabiano Rosas                    int64_t shift, uint32_t opr_sz, uint32_t max_sz)
3116f0984d40SFabiano Rosas {
3117f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
3118f0984d40SFabiano Rosas         INDEX_op_sari_vec, INDEX_op_add_vec, 0
3119f0984d40SFabiano Rosas     };
3120f0984d40SFabiano Rosas     static const GVecGen2i ops[4] = {
3121f0984d40SFabiano Rosas         { .fni8 = gen_ssra8_i64,
3122f0984d40SFabiano Rosas           .fniv = gen_ssra_vec,
3123f0984d40SFabiano Rosas           .fno = gen_helper_gvec_ssra_b,
3124f0984d40SFabiano Rosas           .load_dest = true,
3125f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3126f0984d40SFabiano Rosas           .vece = MO_8 },
3127f0984d40SFabiano Rosas         { .fni8 = gen_ssra16_i64,
3128f0984d40SFabiano Rosas           .fniv = gen_ssra_vec,
3129f0984d40SFabiano Rosas           .fno = gen_helper_gvec_ssra_h,
3130f0984d40SFabiano Rosas           .load_dest = true,
3131f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3132f0984d40SFabiano Rosas           .vece = MO_16 },
3133f0984d40SFabiano Rosas         { .fni4 = gen_ssra32_i32,
3134f0984d40SFabiano Rosas           .fniv = gen_ssra_vec,
3135f0984d40SFabiano Rosas           .fno = gen_helper_gvec_ssra_s,
3136f0984d40SFabiano Rosas           .load_dest = true,
3137f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3138f0984d40SFabiano Rosas           .vece = MO_32 },
3139f0984d40SFabiano Rosas         { .fni8 = gen_ssra64_i64,
3140f0984d40SFabiano Rosas           .fniv = gen_ssra_vec,
3141f0984d40SFabiano Rosas           .fno = gen_helper_gvec_ssra_b,
3142f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
3143f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3144f0984d40SFabiano Rosas           .load_dest = true,
3145f0984d40SFabiano Rosas           .vece = MO_64 },
3146f0984d40SFabiano Rosas     };
3147f0984d40SFabiano Rosas 
3148f0984d40SFabiano Rosas     /* tszimm encoding produces immediates in the range [1..esize]. */
3149f0984d40SFabiano Rosas     tcg_debug_assert(shift > 0);
3150f0984d40SFabiano Rosas     tcg_debug_assert(shift <= (8 << vece));
3151f0984d40SFabiano Rosas 
3152f0984d40SFabiano Rosas     /*
3153f0984d40SFabiano Rosas      * Shifts larger than the element size are architecturally valid.
3154f0984d40SFabiano Rosas      * Signed results in all sign bits.
3155f0984d40SFabiano Rosas      */
3156f0984d40SFabiano Rosas     shift = MIN(shift, (8 << vece) - 1);
3157f0984d40SFabiano Rosas     tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]);
3158f0984d40SFabiano Rosas }
3159f0984d40SFabiano Rosas 
3160f0984d40SFabiano Rosas static void gen_usra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3161f0984d40SFabiano Rosas {
3162f0984d40SFabiano Rosas     tcg_gen_vec_shr8i_i64(a, a, shift);
3163f0984d40SFabiano Rosas     tcg_gen_vec_add8_i64(d, d, a);
3164f0984d40SFabiano Rosas }
3165f0984d40SFabiano Rosas 
3166f0984d40SFabiano Rosas static void gen_usra16_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3167f0984d40SFabiano Rosas {
3168f0984d40SFabiano Rosas     tcg_gen_vec_shr16i_i64(a, a, shift);
3169f0984d40SFabiano Rosas     tcg_gen_vec_add16_i64(d, d, a);
3170f0984d40SFabiano Rosas }
3171f0984d40SFabiano Rosas 
3172f0984d40SFabiano Rosas static void gen_usra32_i32(TCGv_i32 d, TCGv_i32 a, int32_t shift)
3173f0984d40SFabiano Rosas {
3174f0984d40SFabiano Rosas     tcg_gen_shri_i32(a, a, shift);
3175f0984d40SFabiano Rosas     tcg_gen_add_i32(d, d, a);
3176f0984d40SFabiano Rosas }
3177f0984d40SFabiano Rosas 
3178f0984d40SFabiano Rosas static void gen_usra64_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3179f0984d40SFabiano Rosas {
3180f0984d40SFabiano Rosas     tcg_gen_shri_i64(a, a, shift);
3181f0984d40SFabiano Rosas     tcg_gen_add_i64(d, d, a);
3182f0984d40SFabiano Rosas }
3183f0984d40SFabiano Rosas 
3184f0984d40SFabiano Rosas static void gen_usra_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh)
3185f0984d40SFabiano Rosas {
3186f0984d40SFabiano Rosas     tcg_gen_shri_vec(vece, a, a, sh);
3187f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, d, d, a);
3188f0984d40SFabiano Rosas }
3189f0984d40SFabiano Rosas 
3190f0984d40SFabiano Rosas void gen_gvec_usra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
3191f0984d40SFabiano Rosas                    int64_t shift, uint32_t opr_sz, uint32_t max_sz)
3192f0984d40SFabiano Rosas {
3193f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
3194f0984d40SFabiano Rosas         INDEX_op_shri_vec, INDEX_op_add_vec, 0
3195f0984d40SFabiano Rosas     };
3196f0984d40SFabiano Rosas     static const GVecGen2i ops[4] = {
3197f0984d40SFabiano Rosas         { .fni8 = gen_usra8_i64,
3198f0984d40SFabiano Rosas           .fniv = gen_usra_vec,
3199f0984d40SFabiano Rosas           .fno = gen_helper_gvec_usra_b,
3200f0984d40SFabiano Rosas           .load_dest = true,
3201f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3202f0984d40SFabiano Rosas           .vece = MO_8, },
3203f0984d40SFabiano Rosas         { .fni8 = gen_usra16_i64,
3204f0984d40SFabiano Rosas           .fniv = gen_usra_vec,
3205f0984d40SFabiano Rosas           .fno = gen_helper_gvec_usra_h,
3206f0984d40SFabiano Rosas           .load_dest = true,
3207f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3208f0984d40SFabiano Rosas           .vece = MO_16, },
3209f0984d40SFabiano Rosas         { .fni4 = gen_usra32_i32,
3210f0984d40SFabiano Rosas           .fniv = gen_usra_vec,
3211f0984d40SFabiano Rosas           .fno = gen_helper_gvec_usra_s,
3212f0984d40SFabiano Rosas           .load_dest = true,
3213f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3214f0984d40SFabiano Rosas           .vece = MO_32, },
3215f0984d40SFabiano Rosas         { .fni8 = gen_usra64_i64,
3216f0984d40SFabiano Rosas           .fniv = gen_usra_vec,
3217f0984d40SFabiano Rosas           .fno = gen_helper_gvec_usra_d,
3218f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
3219f0984d40SFabiano Rosas           .load_dest = true,
3220f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3221f0984d40SFabiano Rosas           .vece = MO_64, },
3222f0984d40SFabiano Rosas     };
3223f0984d40SFabiano Rosas 
3224f0984d40SFabiano Rosas     /* tszimm encoding produces immediates in the range [1..esize]. */
3225f0984d40SFabiano Rosas     tcg_debug_assert(shift > 0);
3226f0984d40SFabiano Rosas     tcg_debug_assert(shift <= (8 << vece));
3227f0984d40SFabiano Rosas 
3228f0984d40SFabiano Rosas     /*
3229f0984d40SFabiano Rosas      * Shifts larger than the element size are architecturally valid.
3230f0984d40SFabiano Rosas      * Unsigned results in all zeros as input to accumulate: nop.
3231f0984d40SFabiano Rosas      */
3232f0984d40SFabiano Rosas     if (shift < (8 << vece)) {
3233f0984d40SFabiano Rosas         tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]);
3234f0984d40SFabiano Rosas     } else {
3235f0984d40SFabiano Rosas         /* Nop, but we do need to clear the tail. */
3236f0984d40SFabiano Rosas         tcg_gen_gvec_mov(vece, rd_ofs, rd_ofs, opr_sz, max_sz);
3237f0984d40SFabiano Rosas     }
3238f0984d40SFabiano Rosas }
3239f0984d40SFabiano Rosas 
3240f0984d40SFabiano Rosas /*
3241f0984d40SFabiano Rosas  * Shift one less than the requested amount, and the low bit is
3242f0984d40SFabiano Rosas  * the rounding bit.  For the 8 and 16-bit operations, because we
3243f0984d40SFabiano Rosas  * mask the low bit, we can perform a normal integer shift instead
3244f0984d40SFabiano Rosas  * of a vector shift.
3245f0984d40SFabiano Rosas  */
3246f0984d40SFabiano Rosas static void gen_srshr8_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3247f0984d40SFabiano Rosas {
3248f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3249f0984d40SFabiano Rosas 
3250f0984d40SFabiano Rosas     tcg_gen_shri_i64(t, a, sh - 1);
3251f0984d40SFabiano Rosas     tcg_gen_andi_i64(t, t, dup_const(MO_8, 1));
3252f0984d40SFabiano Rosas     tcg_gen_vec_sar8i_i64(d, a, sh);
3253f0984d40SFabiano Rosas     tcg_gen_vec_add8_i64(d, d, t);
3254f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3255f0984d40SFabiano Rosas }
3256f0984d40SFabiano Rosas 
3257f0984d40SFabiano Rosas static void gen_srshr16_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3258f0984d40SFabiano Rosas {
3259f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3260f0984d40SFabiano Rosas 
3261f0984d40SFabiano Rosas     tcg_gen_shri_i64(t, a, sh - 1);
3262f0984d40SFabiano Rosas     tcg_gen_andi_i64(t, t, dup_const(MO_16, 1));
3263f0984d40SFabiano Rosas     tcg_gen_vec_sar16i_i64(d, a, sh);
3264f0984d40SFabiano Rosas     tcg_gen_vec_add16_i64(d, d, t);
3265f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3266f0984d40SFabiano Rosas }
3267f0984d40SFabiano Rosas 
3268f0984d40SFabiano Rosas static void gen_srshr32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh)
3269f0984d40SFabiano Rosas {
3270f0984d40SFabiano Rosas     TCGv_i32 t;
3271f0984d40SFabiano Rosas 
3272f0984d40SFabiano Rosas     /* Handle shift by the input size for the benefit of trans_SRSHR_ri */
3273f0984d40SFabiano Rosas     if (sh == 32) {
3274f0984d40SFabiano Rosas         tcg_gen_movi_i32(d, 0);
3275f0984d40SFabiano Rosas         return;
3276f0984d40SFabiano Rosas     }
3277f0984d40SFabiano Rosas     t = tcg_temp_new_i32();
3278f0984d40SFabiano Rosas     tcg_gen_extract_i32(t, a, sh - 1, 1);
3279f0984d40SFabiano Rosas     tcg_gen_sari_i32(d, a, sh);
3280f0984d40SFabiano Rosas     tcg_gen_add_i32(d, d, t);
3281f0984d40SFabiano Rosas     tcg_temp_free_i32(t);
3282f0984d40SFabiano Rosas }
3283f0984d40SFabiano Rosas 
3284f0984d40SFabiano Rosas static void gen_srshr64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3285f0984d40SFabiano Rosas {
3286f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3287f0984d40SFabiano Rosas 
3288f0984d40SFabiano Rosas     tcg_gen_extract_i64(t, a, sh - 1, 1);
3289f0984d40SFabiano Rosas     tcg_gen_sari_i64(d, a, sh);
3290f0984d40SFabiano Rosas     tcg_gen_add_i64(d, d, t);
3291f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3292f0984d40SFabiano Rosas }
3293f0984d40SFabiano Rosas 
3294f0984d40SFabiano Rosas static void gen_srshr_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh)
3295f0984d40SFabiano Rosas {
3296f0984d40SFabiano Rosas     TCGv_vec t = tcg_temp_new_vec_matching(d);
3297f0984d40SFabiano Rosas     TCGv_vec ones = tcg_temp_new_vec_matching(d);
3298f0984d40SFabiano Rosas 
3299f0984d40SFabiano Rosas     tcg_gen_shri_vec(vece, t, a, sh - 1);
3300f0984d40SFabiano Rosas     tcg_gen_dupi_vec(vece, ones, 1);
3301f0984d40SFabiano Rosas     tcg_gen_and_vec(vece, t, t, ones);
3302f0984d40SFabiano Rosas     tcg_gen_sari_vec(vece, d, a, sh);
3303f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, d, d, t);
3304f0984d40SFabiano Rosas 
3305f0984d40SFabiano Rosas     tcg_temp_free_vec(t);
3306f0984d40SFabiano Rosas     tcg_temp_free_vec(ones);
3307f0984d40SFabiano Rosas }
3308f0984d40SFabiano Rosas 
3309f0984d40SFabiano Rosas void gen_gvec_srshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
3310f0984d40SFabiano Rosas                     int64_t shift, uint32_t opr_sz, uint32_t max_sz)
3311f0984d40SFabiano Rosas {
3312f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
3313f0984d40SFabiano Rosas         INDEX_op_shri_vec, INDEX_op_sari_vec, INDEX_op_add_vec, 0
3314f0984d40SFabiano Rosas     };
3315f0984d40SFabiano Rosas     static const GVecGen2i ops[4] = {
3316f0984d40SFabiano Rosas         { .fni8 = gen_srshr8_i64,
3317f0984d40SFabiano Rosas           .fniv = gen_srshr_vec,
3318f0984d40SFabiano Rosas           .fno = gen_helper_gvec_srshr_b,
3319f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3320f0984d40SFabiano Rosas           .vece = MO_8 },
3321f0984d40SFabiano Rosas         { .fni8 = gen_srshr16_i64,
3322f0984d40SFabiano Rosas           .fniv = gen_srshr_vec,
3323f0984d40SFabiano Rosas           .fno = gen_helper_gvec_srshr_h,
3324f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3325f0984d40SFabiano Rosas           .vece = MO_16 },
3326f0984d40SFabiano Rosas         { .fni4 = gen_srshr32_i32,
3327f0984d40SFabiano Rosas           .fniv = gen_srshr_vec,
3328f0984d40SFabiano Rosas           .fno = gen_helper_gvec_srshr_s,
3329f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3330f0984d40SFabiano Rosas           .vece = MO_32 },
3331f0984d40SFabiano Rosas         { .fni8 = gen_srshr64_i64,
3332f0984d40SFabiano Rosas           .fniv = gen_srshr_vec,
3333f0984d40SFabiano Rosas           .fno = gen_helper_gvec_srshr_d,
3334f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
3335f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3336f0984d40SFabiano Rosas           .vece = MO_64 },
3337f0984d40SFabiano Rosas     };
3338f0984d40SFabiano Rosas 
3339f0984d40SFabiano Rosas     /* tszimm encoding produces immediates in the range [1..esize] */
3340f0984d40SFabiano Rosas     tcg_debug_assert(shift > 0);
3341f0984d40SFabiano Rosas     tcg_debug_assert(shift <= (8 << vece));
3342f0984d40SFabiano Rosas 
3343f0984d40SFabiano Rosas     if (shift == (8 << vece)) {
3344f0984d40SFabiano Rosas         /*
3345f0984d40SFabiano Rosas          * Shifts larger than the element size are architecturally valid.
3346f0984d40SFabiano Rosas          * Signed results in all sign bits.  With rounding, this produces
3347f0984d40SFabiano Rosas          *   (-1 + 1) >> 1 == 0, or (0 + 1) >> 1 == 0.
3348f0984d40SFabiano Rosas          * I.e. always zero.
3349f0984d40SFabiano Rosas          */
3350f0984d40SFabiano Rosas         tcg_gen_gvec_dup_imm(vece, rd_ofs, opr_sz, max_sz, 0);
3351f0984d40SFabiano Rosas     } else {
3352f0984d40SFabiano Rosas         tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]);
3353f0984d40SFabiano Rosas     }
3354f0984d40SFabiano Rosas }
3355f0984d40SFabiano Rosas 
3356f0984d40SFabiano Rosas static void gen_srsra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3357f0984d40SFabiano Rosas {
3358f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3359f0984d40SFabiano Rosas 
3360f0984d40SFabiano Rosas     gen_srshr8_i64(t, a, sh);
3361f0984d40SFabiano Rosas     tcg_gen_vec_add8_i64(d, d, t);
3362f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3363f0984d40SFabiano Rosas }
3364f0984d40SFabiano Rosas 
3365f0984d40SFabiano Rosas static void gen_srsra16_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3366f0984d40SFabiano Rosas {
3367f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3368f0984d40SFabiano Rosas 
3369f0984d40SFabiano Rosas     gen_srshr16_i64(t, a, sh);
3370f0984d40SFabiano Rosas     tcg_gen_vec_add16_i64(d, d, t);
3371f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3372f0984d40SFabiano Rosas }
3373f0984d40SFabiano Rosas 
3374f0984d40SFabiano Rosas static void gen_srsra32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh)
3375f0984d40SFabiano Rosas {
3376f0984d40SFabiano Rosas     TCGv_i32 t = tcg_temp_new_i32();
3377f0984d40SFabiano Rosas 
3378f0984d40SFabiano Rosas     gen_srshr32_i32(t, a, sh);
3379f0984d40SFabiano Rosas     tcg_gen_add_i32(d, d, t);
3380f0984d40SFabiano Rosas     tcg_temp_free_i32(t);
3381f0984d40SFabiano Rosas }
3382f0984d40SFabiano Rosas 
3383f0984d40SFabiano Rosas static void gen_srsra64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3384f0984d40SFabiano Rosas {
3385f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3386f0984d40SFabiano Rosas 
3387f0984d40SFabiano Rosas     gen_srshr64_i64(t, a, sh);
3388f0984d40SFabiano Rosas     tcg_gen_add_i64(d, d, t);
3389f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3390f0984d40SFabiano Rosas }
3391f0984d40SFabiano Rosas 
3392f0984d40SFabiano Rosas static void gen_srsra_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh)
3393f0984d40SFabiano Rosas {
3394f0984d40SFabiano Rosas     TCGv_vec t = tcg_temp_new_vec_matching(d);
3395f0984d40SFabiano Rosas 
3396f0984d40SFabiano Rosas     gen_srshr_vec(vece, t, a, sh);
3397f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, d, d, t);
3398f0984d40SFabiano Rosas     tcg_temp_free_vec(t);
3399f0984d40SFabiano Rosas }
3400f0984d40SFabiano Rosas 
3401f0984d40SFabiano Rosas void gen_gvec_srsra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
3402f0984d40SFabiano Rosas                     int64_t shift, uint32_t opr_sz, uint32_t max_sz)
3403f0984d40SFabiano Rosas {
3404f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
3405f0984d40SFabiano Rosas         INDEX_op_shri_vec, INDEX_op_sari_vec, INDEX_op_add_vec, 0
3406f0984d40SFabiano Rosas     };
3407f0984d40SFabiano Rosas     static const GVecGen2i ops[4] = {
3408f0984d40SFabiano Rosas         { .fni8 = gen_srsra8_i64,
3409f0984d40SFabiano Rosas           .fniv = gen_srsra_vec,
3410f0984d40SFabiano Rosas           .fno = gen_helper_gvec_srsra_b,
3411f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3412f0984d40SFabiano Rosas           .load_dest = true,
3413f0984d40SFabiano Rosas           .vece = MO_8 },
3414f0984d40SFabiano Rosas         { .fni8 = gen_srsra16_i64,
3415f0984d40SFabiano Rosas           .fniv = gen_srsra_vec,
3416f0984d40SFabiano Rosas           .fno = gen_helper_gvec_srsra_h,
3417f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3418f0984d40SFabiano Rosas           .load_dest = true,
3419f0984d40SFabiano Rosas           .vece = MO_16 },
3420f0984d40SFabiano Rosas         { .fni4 = gen_srsra32_i32,
3421f0984d40SFabiano Rosas           .fniv = gen_srsra_vec,
3422f0984d40SFabiano Rosas           .fno = gen_helper_gvec_srsra_s,
3423f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3424f0984d40SFabiano Rosas           .load_dest = true,
3425f0984d40SFabiano Rosas           .vece = MO_32 },
3426f0984d40SFabiano Rosas         { .fni8 = gen_srsra64_i64,
3427f0984d40SFabiano Rosas           .fniv = gen_srsra_vec,
3428f0984d40SFabiano Rosas           .fno = gen_helper_gvec_srsra_d,
3429f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
3430f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3431f0984d40SFabiano Rosas           .load_dest = true,
3432f0984d40SFabiano Rosas           .vece = MO_64 },
3433f0984d40SFabiano Rosas     };
3434f0984d40SFabiano Rosas 
3435f0984d40SFabiano Rosas     /* tszimm encoding produces immediates in the range [1..esize] */
3436f0984d40SFabiano Rosas     tcg_debug_assert(shift > 0);
3437f0984d40SFabiano Rosas     tcg_debug_assert(shift <= (8 << vece));
3438f0984d40SFabiano Rosas 
3439f0984d40SFabiano Rosas     /*
3440f0984d40SFabiano Rosas      * Shifts larger than the element size are architecturally valid.
3441f0984d40SFabiano Rosas      * Signed results in all sign bits.  With rounding, this produces
3442f0984d40SFabiano Rosas      *   (-1 + 1) >> 1 == 0, or (0 + 1) >> 1 == 0.
3443f0984d40SFabiano Rosas      * I.e. always zero.  With accumulation, this leaves D unchanged.
3444f0984d40SFabiano Rosas      */
3445f0984d40SFabiano Rosas     if (shift == (8 << vece)) {
3446f0984d40SFabiano Rosas         /* Nop, but we do need to clear the tail. */
3447f0984d40SFabiano Rosas         tcg_gen_gvec_mov(vece, rd_ofs, rd_ofs, opr_sz, max_sz);
3448f0984d40SFabiano Rosas     } else {
3449f0984d40SFabiano Rosas         tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]);
3450f0984d40SFabiano Rosas     }
3451f0984d40SFabiano Rosas }
3452f0984d40SFabiano Rosas 
3453f0984d40SFabiano Rosas static void gen_urshr8_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3454f0984d40SFabiano Rosas {
3455f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3456f0984d40SFabiano Rosas 
3457f0984d40SFabiano Rosas     tcg_gen_shri_i64(t, a, sh - 1);
3458f0984d40SFabiano Rosas     tcg_gen_andi_i64(t, t, dup_const(MO_8, 1));
3459f0984d40SFabiano Rosas     tcg_gen_vec_shr8i_i64(d, a, sh);
3460f0984d40SFabiano Rosas     tcg_gen_vec_add8_i64(d, d, t);
3461f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3462f0984d40SFabiano Rosas }
3463f0984d40SFabiano Rosas 
3464f0984d40SFabiano Rosas static void gen_urshr16_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3465f0984d40SFabiano Rosas {
3466f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3467f0984d40SFabiano Rosas 
3468f0984d40SFabiano Rosas     tcg_gen_shri_i64(t, a, sh - 1);
3469f0984d40SFabiano Rosas     tcg_gen_andi_i64(t, t, dup_const(MO_16, 1));
3470f0984d40SFabiano Rosas     tcg_gen_vec_shr16i_i64(d, a, sh);
3471f0984d40SFabiano Rosas     tcg_gen_vec_add16_i64(d, d, t);
3472f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3473f0984d40SFabiano Rosas }
3474f0984d40SFabiano Rosas 
3475f0984d40SFabiano Rosas static void gen_urshr32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh)
3476f0984d40SFabiano Rosas {
3477f0984d40SFabiano Rosas     TCGv_i32 t;
3478f0984d40SFabiano Rosas 
3479f0984d40SFabiano Rosas     /* Handle shift by the input size for the benefit of trans_URSHR_ri */
3480f0984d40SFabiano Rosas     if (sh == 32) {
3481f0984d40SFabiano Rosas         tcg_gen_extract_i32(d, a, sh - 1, 1);
3482f0984d40SFabiano Rosas         return;
3483f0984d40SFabiano Rosas     }
3484f0984d40SFabiano Rosas     t = tcg_temp_new_i32();
3485f0984d40SFabiano Rosas     tcg_gen_extract_i32(t, a, sh - 1, 1);
3486f0984d40SFabiano Rosas     tcg_gen_shri_i32(d, a, sh);
3487f0984d40SFabiano Rosas     tcg_gen_add_i32(d, d, t);
3488f0984d40SFabiano Rosas     tcg_temp_free_i32(t);
3489f0984d40SFabiano Rosas }
3490f0984d40SFabiano Rosas 
3491f0984d40SFabiano Rosas static void gen_urshr64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3492f0984d40SFabiano Rosas {
3493f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3494f0984d40SFabiano Rosas 
3495f0984d40SFabiano Rosas     tcg_gen_extract_i64(t, a, sh - 1, 1);
3496f0984d40SFabiano Rosas     tcg_gen_shri_i64(d, a, sh);
3497f0984d40SFabiano Rosas     tcg_gen_add_i64(d, d, t);
3498f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3499f0984d40SFabiano Rosas }
3500f0984d40SFabiano Rosas 
3501f0984d40SFabiano Rosas static void gen_urshr_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t shift)
3502f0984d40SFabiano Rosas {
3503f0984d40SFabiano Rosas     TCGv_vec t = tcg_temp_new_vec_matching(d);
3504f0984d40SFabiano Rosas     TCGv_vec ones = tcg_temp_new_vec_matching(d);
3505f0984d40SFabiano Rosas 
3506f0984d40SFabiano Rosas     tcg_gen_shri_vec(vece, t, a, shift - 1);
3507f0984d40SFabiano Rosas     tcg_gen_dupi_vec(vece, ones, 1);
3508f0984d40SFabiano Rosas     tcg_gen_and_vec(vece, t, t, ones);
3509f0984d40SFabiano Rosas     tcg_gen_shri_vec(vece, d, a, shift);
3510f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, d, d, t);
3511f0984d40SFabiano Rosas 
3512f0984d40SFabiano Rosas     tcg_temp_free_vec(t);
3513f0984d40SFabiano Rosas     tcg_temp_free_vec(ones);
3514f0984d40SFabiano Rosas }
3515f0984d40SFabiano Rosas 
3516f0984d40SFabiano Rosas void gen_gvec_urshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
3517f0984d40SFabiano Rosas                     int64_t shift, uint32_t opr_sz, uint32_t max_sz)
3518f0984d40SFabiano Rosas {
3519f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
3520f0984d40SFabiano Rosas         INDEX_op_shri_vec, INDEX_op_add_vec, 0
3521f0984d40SFabiano Rosas     };
3522f0984d40SFabiano Rosas     static const GVecGen2i ops[4] = {
3523f0984d40SFabiano Rosas         { .fni8 = gen_urshr8_i64,
3524f0984d40SFabiano Rosas           .fniv = gen_urshr_vec,
3525f0984d40SFabiano Rosas           .fno = gen_helper_gvec_urshr_b,
3526f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3527f0984d40SFabiano Rosas           .vece = MO_8 },
3528f0984d40SFabiano Rosas         { .fni8 = gen_urshr16_i64,
3529f0984d40SFabiano Rosas           .fniv = gen_urshr_vec,
3530f0984d40SFabiano Rosas           .fno = gen_helper_gvec_urshr_h,
3531f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3532f0984d40SFabiano Rosas           .vece = MO_16 },
3533f0984d40SFabiano Rosas         { .fni4 = gen_urshr32_i32,
3534f0984d40SFabiano Rosas           .fniv = gen_urshr_vec,
3535f0984d40SFabiano Rosas           .fno = gen_helper_gvec_urshr_s,
3536f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3537f0984d40SFabiano Rosas           .vece = MO_32 },
3538f0984d40SFabiano Rosas         { .fni8 = gen_urshr64_i64,
3539f0984d40SFabiano Rosas           .fniv = gen_urshr_vec,
3540f0984d40SFabiano Rosas           .fno = gen_helper_gvec_urshr_d,
3541f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
3542f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3543f0984d40SFabiano Rosas           .vece = MO_64 },
3544f0984d40SFabiano Rosas     };
3545f0984d40SFabiano Rosas 
3546f0984d40SFabiano Rosas     /* tszimm encoding produces immediates in the range [1..esize] */
3547f0984d40SFabiano Rosas     tcg_debug_assert(shift > 0);
3548f0984d40SFabiano Rosas     tcg_debug_assert(shift <= (8 << vece));
3549f0984d40SFabiano Rosas 
3550f0984d40SFabiano Rosas     if (shift == (8 << vece)) {
3551f0984d40SFabiano Rosas         /*
3552f0984d40SFabiano Rosas          * Shifts larger than the element size are architecturally valid.
3553f0984d40SFabiano Rosas          * Unsigned results in zero.  With rounding, this produces a
3554f0984d40SFabiano Rosas          * copy of the most significant bit.
3555f0984d40SFabiano Rosas          */
3556f0984d40SFabiano Rosas         tcg_gen_gvec_shri(vece, rd_ofs, rm_ofs, shift - 1, opr_sz, max_sz);
3557f0984d40SFabiano Rosas     } else {
3558f0984d40SFabiano Rosas         tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]);
3559f0984d40SFabiano Rosas     }
3560f0984d40SFabiano Rosas }
3561f0984d40SFabiano Rosas 
3562f0984d40SFabiano Rosas static void gen_ursra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3563f0984d40SFabiano Rosas {
3564f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3565f0984d40SFabiano Rosas 
3566f0984d40SFabiano Rosas     if (sh == 8) {
3567f0984d40SFabiano Rosas         tcg_gen_vec_shr8i_i64(t, a, 7);
3568f0984d40SFabiano Rosas     } else {
3569f0984d40SFabiano Rosas         gen_urshr8_i64(t, a, sh);
3570f0984d40SFabiano Rosas     }
3571f0984d40SFabiano Rosas     tcg_gen_vec_add8_i64(d, d, t);
3572f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3573f0984d40SFabiano Rosas }
3574f0984d40SFabiano Rosas 
3575f0984d40SFabiano Rosas static void gen_ursra16_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3576f0984d40SFabiano Rosas {
3577f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3578f0984d40SFabiano Rosas 
3579f0984d40SFabiano Rosas     if (sh == 16) {
3580f0984d40SFabiano Rosas         tcg_gen_vec_shr16i_i64(t, a, 15);
3581f0984d40SFabiano Rosas     } else {
3582f0984d40SFabiano Rosas         gen_urshr16_i64(t, a, sh);
3583f0984d40SFabiano Rosas     }
3584f0984d40SFabiano Rosas     tcg_gen_vec_add16_i64(d, d, t);
3585f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3586f0984d40SFabiano Rosas }
3587f0984d40SFabiano Rosas 
3588f0984d40SFabiano Rosas static void gen_ursra32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh)
3589f0984d40SFabiano Rosas {
3590f0984d40SFabiano Rosas     TCGv_i32 t = tcg_temp_new_i32();
3591f0984d40SFabiano Rosas 
3592f0984d40SFabiano Rosas     if (sh == 32) {
3593f0984d40SFabiano Rosas         tcg_gen_shri_i32(t, a, 31);
3594f0984d40SFabiano Rosas     } else {
3595f0984d40SFabiano Rosas         gen_urshr32_i32(t, a, sh);
3596f0984d40SFabiano Rosas     }
3597f0984d40SFabiano Rosas     tcg_gen_add_i32(d, d, t);
3598f0984d40SFabiano Rosas     tcg_temp_free_i32(t);
3599f0984d40SFabiano Rosas }
3600f0984d40SFabiano Rosas 
3601f0984d40SFabiano Rosas static void gen_ursra64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
3602f0984d40SFabiano Rosas {
3603f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3604f0984d40SFabiano Rosas 
3605f0984d40SFabiano Rosas     if (sh == 64) {
3606f0984d40SFabiano Rosas         tcg_gen_shri_i64(t, a, 63);
3607f0984d40SFabiano Rosas     } else {
3608f0984d40SFabiano Rosas         gen_urshr64_i64(t, a, sh);
3609f0984d40SFabiano Rosas     }
3610f0984d40SFabiano Rosas     tcg_gen_add_i64(d, d, t);
3611f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3612f0984d40SFabiano Rosas }
3613f0984d40SFabiano Rosas 
3614f0984d40SFabiano Rosas static void gen_ursra_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh)
3615f0984d40SFabiano Rosas {
3616f0984d40SFabiano Rosas     TCGv_vec t = tcg_temp_new_vec_matching(d);
3617f0984d40SFabiano Rosas 
3618f0984d40SFabiano Rosas     if (sh == (8 << vece)) {
3619f0984d40SFabiano Rosas         tcg_gen_shri_vec(vece, t, a, sh - 1);
3620f0984d40SFabiano Rosas     } else {
3621f0984d40SFabiano Rosas         gen_urshr_vec(vece, t, a, sh);
3622f0984d40SFabiano Rosas     }
3623f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, d, d, t);
3624f0984d40SFabiano Rosas     tcg_temp_free_vec(t);
3625f0984d40SFabiano Rosas }
3626f0984d40SFabiano Rosas 
3627f0984d40SFabiano Rosas void gen_gvec_ursra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
3628f0984d40SFabiano Rosas                     int64_t shift, uint32_t opr_sz, uint32_t max_sz)
3629f0984d40SFabiano Rosas {
3630f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
3631f0984d40SFabiano Rosas         INDEX_op_shri_vec, INDEX_op_add_vec, 0
3632f0984d40SFabiano Rosas     };
3633f0984d40SFabiano Rosas     static const GVecGen2i ops[4] = {
3634f0984d40SFabiano Rosas         { .fni8 = gen_ursra8_i64,
3635f0984d40SFabiano Rosas           .fniv = gen_ursra_vec,
3636f0984d40SFabiano Rosas           .fno = gen_helper_gvec_ursra_b,
3637f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3638f0984d40SFabiano Rosas           .load_dest = true,
3639f0984d40SFabiano Rosas           .vece = MO_8 },
3640f0984d40SFabiano Rosas         { .fni8 = gen_ursra16_i64,
3641f0984d40SFabiano Rosas           .fniv = gen_ursra_vec,
3642f0984d40SFabiano Rosas           .fno = gen_helper_gvec_ursra_h,
3643f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3644f0984d40SFabiano Rosas           .load_dest = true,
3645f0984d40SFabiano Rosas           .vece = MO_16 },
3646f0984d40SFabiano Rosas         { .fni4 = gen_ursra32_i32,
3647f0984d40SFabiano Rosas           .fniv = gen_ursra_vec,
3648f0984d40SFabiano Rosas           .fno = gen_helper_gvec_ursra_s,
3649f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3650f0984d40SFabiano Rosas           .load_dest = true,
3651f0984d40SFabiano Rosas           .vece = MO_32 },
3652f0984d40SFabiano Rosas         { .fni8 = gen_ursra64_i64,
3653f0984d40SFabiano Rosas           .fniv = gen_ursra_vec,
3654f0984d40SFabiano Rosas           .fno = gen_helper_gvec_ursra_d,
3655f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
3656f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3657f0984d40SFabiano Rosas           .load_dest = true,
3658f0984d40SFabiano Rosas           .vece = MO_64 },
3659f0984d40SFabiano Rosas     };
3660f0984d40SFabiano Rosas 
3661f0984d40SFabiano Rosas     /* tszimm encoding produces immediates in the range [1..esize] */
3662f0984d40SFabiano Rosas     tcg_debug_assert(shift > 0);
3663f0984d40SFabiano Rosas     tcg_debug_assert(shift <= (8 << vece));
3664f0984d40SFabiano Rosas 
3665f0984d40SFabiano Rosas     tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]);
3666f0984d40SFabiano Rosas }
3667f0984d40SFabiano Rosas 
3668f0984d40SFabiano Rosas static void gen_shr8_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3669f0984d40SFabiano Rosas {
3670f0984d40SFabiano Rosas     uint64_t mask = dup_const(MO_8, 0xff >> shift);
3671f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3672f0984d40SFabiano Rosas 
3673f0984d40SFabiano Rosas     tcg_gen_shri_i64(t, a, shift);
3674f0984d40SFabiano Rosas     tcg_gen_andi_i64(t, t, mask);
3675f0984d40SFabiano Rosas     tcg_gen_andi_i64(d, d, ~mask);
3676f0984d40SFabiano Rosas     tcg_gen_or_i64(d, d, t);
3677f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3678f0984d40SFabiano Rosas }
3679f0984d40SFabiano Rosas 
3680f0984d40SFabiano Rosas static void gen_shr16_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3681f0984d40SFabiano Rosas {
3682f0984d40SFabiano Rosas     uint64_t mask = dup_const(MO_16, 0xffff >> shift);
3683f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3684f0984d40SFabiano Rosas 
3685f0984d40SFabiano Rosas     tcg_gen_shri_i64(t, a, shift);
3686f0984d40SFabiano Rosas     tcg_gen_andi_i64(t, t, mask);
3687f0984d40SFabiano Rosas     tcg_gen_andi_i64(d, d, ~mask);
3688f0984d40SFabiano Rosas     tcg_gen_or_i64(d, d, t);
3689f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3690f0984d40SFabiano Rosas }
3691f0984d40SFabiano Rosas 
3692f0984d40SFabiano Rosas static void gen_shr32_ins_i32(TCGv_i32 d, TCGv_i32 a, int32_t shift)
3693f0984d40SFabiano Rosas {
3694f0984d40SFabiano Rosas     tcg_gen_shri_i32(a, a, shift);
3695f0984d40SFabiano Rosas     tcg_gen_deposit_i32(d, d, a, 0, 32 - shift);
3696f0984d40SFabiano Rosas }
3697f0984d40SFabiano Rosas 
3698f0984d40SFabiano Rosas static void gen_shr64_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3699f0984d40SFabiano Rosas {
3700f0984d40SFabiano Rosas     tcg_gen_shri_i64(a, a, shift);
3701f0984d40SFabiano Rosas     tcg_gen_deposit_i64(d, d, a, 0, 64 - shift);
3702f0984d40SFabiano Rosas }
3703f0984d40SFabiano Rosas 
3704f0984d40SFabiano Rosas static void gen_shr_ins_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh)
3705f0984d40SFabiano Rosas {
3706f0984d40SFabiano Rosas     TCGv_vec t = tcg_temp_new_vec_matching(d);
3707f0984d40SFabiano Rosas     TCGv_vec m = tcg_temp_new_vec_matching(d);
3708f0984d40SFabiano Rosas 
3709f0984d40SFabiano Rosas     tcg_gen_dupi_vec(vece, m, MAKE_64BIT_MASK((8 << vece) - sh, sh));
3710f0984d40SFabiano Rosas     tcg_gen_shri_vec(vece, t, a, sh);
3711f0984d40SFabiano Rosas     tcg_gen_and_vec(vece, d, d, m);
3712f0984d40SFabiano Rosas     tcg_gen_or_vec(vece, d, d, t);
3713f0984d40SFabiano Rosas 
3714f0984d40SFabiano Rosas     tcg_temp_free_vec(t);
3715f0984d40SFabiano Rosas     tcg_temp_free_vec(m);
3716f0984d40SFabiano Rosas }
3717f0984d40SFabiano Rosas 
3718f0984d40SFabiano Rosas void gen_gvec_sri(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
3719f0984d40SFabiano Rosas                   int64_t shift, uint32_t opr_sz, uint32_t max_sz)
3720f0984d40SFabiano Rosas {
3721f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = { INDEX_op_shri_vec, 0 };
3722f0984d40SFabiano Rosas     const GVecGen2i ops[4] = {
3723f0984d40SFabiano Rosas         { .fni8 = gen_shr8_ins_i64,
3724f0984d40SFabiano Rosas           .fniv = gen_shr_ins_vec,
3725f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sri_b,
3726f0984d40SFabiano Rosas           .load_dest = true,
3727f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3728f0984d40SFabiano Rosas           .vece = MO_8 },
3729f0984d40SFabiano Rosas         { .fni8 = gen_shr16_ins_i64,
3730f0984d40SFabiano Rosas           .fniv = gen_shr_ins_vec,
3731f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sri_h,
3732f0984d40SFabiano Rosas           .load_dest = true,
3733f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3734f0984d40SFabiano Rosas           .vece = MO_16 },
3735f0984d40SFabiano Rosas         { .fni4 = gen_shr32_ins_i32,
3736f0984d40SFabiano Rosas           .fniv = gen_shr_ins_vec,
3737f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sri_s,
3738f0984d40SFabiano Rosas           .load_dest = true,
3739f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3740f0984d40SFabiano Rosas           .vece = MO_32 },
3741f0984d40SFabiano Rosas         { .fni8 = gen_shr64_ins_i64,
3742f0984d40SFabiano Rosas           .fniv = gen_shr_ins_vec,
3743f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sri_d,
3744f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
3745f0984d40SFabiano Rosas           .load_dest = true,
3746f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3747f0984d40SFabiano Rosas           .vece = MO_64 },
3748f0984d40SFabiano Rosas     };
3749f0984d40SFabiano Rosas 
3750f0984d40SFabiano Rosas     /* tszimm encoding produces immediates in the range [1..esize]. */
3751f0984d40SFabiano Rosas     tcg_debug_assert(shift > 0);
3752f0984d40SFabiano Rosas     tcg_debug_assert(shift <= (8 << vece));
3753f0984d40SFabiano Rosas 
3754f0984d40SFabiano Rosas     /* Shift of esize leaves destination unchanged. */
3755f0984d40SFabiano Rosas     if (shift < (8 << vece)) {
3756f0984d40SFabiano Rosas         tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]);
3757f0984d40SFabiano Rosas     } else {
3758f0984d40SFabiano Rosas         /* Nop, but we do need to clear the tail. */
3759f0984d40SFabiano Rosas         tcg_gen_gvec_mov(vece, rd_ofs, rd_ofs, opr_sz, max_sz);
3760f0984d40SFabiano Rosas     }
3761f0984d40SFabiano Rosas }
3762f0984d40SFabiano Rosas 
3763f0984d40SFabiano Rosas static void gen_shl8_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3764f0984d40SFabiano Rosas {
3765f0984d40SFabiano Rosas     uint64_t mask = dup_const(MO_8, 0xff << shift);
3766f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3767f0984d40SFabiano Rosas 
3768f0984d40SFabiano Rosas     tcg_gen_shli_i64(t, a, shift);
3769f0984d40SFabiano Rosas     tcg_gen_andi_i64(t, t, mask);
3770f0984d40SFabiano Rosas     tcg_gen_andi_i64(d, d, ~mask);
3771f0984d40SFabiano Rosas     tcg_gen_or_i64(d, d, t);
3772f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3773f0984d40SFabiano Rosas }
3774f0984d40SFabiano Rosas 
3775f0984d40SFabiano Rosas static void gen_shl16_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3776f0984d40SFabiano Rosas {
3777f0984d40SFabiano Rosas     uint64_t mask = dup_const(MO_16, 0xffff << shift);
3778f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
3779f0984d40SFabiano Rosas 
3780f0984d40SFabiano Rosas     tcg_gen_shli_i64(t, a, shift);
3781f0984d40SFabiano Rosas     tcg_gen_andi_i64(t, t, mask);
3782f0984d40SFabiano Rosas     tcg_gen_andi_i64(d, d, ~mask);
3783f0984d40SFabiano Rosas     tcg_gen_or_i64(d, d, t);
3784f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
3785f0984d40SFabiano Rosas }
3786f0984d40SFabiano Rosas 
3787f0984d40SFabiano Rosas static void gen_shl32_ins_i32(TCGv_i32 d, TCGv_i32 a, int32_t shift)
3788f0984d40SFabiano Rosas {
3789f0984d40SFabiano Rosas     tcg_gen_deposit_i32(d, d, a, shift, 32 - shift);
3790f0984d40SFabiano Rosas }
3791f0984d40SFabiano Rosas 
3792f0984d40SFabiano Rosas static void gen_shl64_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
3793f0984d40SFabiano Rosas {
3794f0984d40SFabiano Rosas     tcg_gen_deposit_i64(d, d, a, shift, 64 - shift);
3795f0984d40SFabiano Rosas }
3796f0984d40SFabiano Rosas 
3797f0984d40SFabiano Rosas static void gen_shl_ins_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh)
3798f0984d40SFabiano Rosas {
3799f0984d40SFabiano Rosas     TCGv_vec t = tcg_temp_new_vec_matching(d);
3800f0984d40SFabiano Rosas     TCGv_vec m = tcg_temp_new_vec_matching(d);
3801f0984d40SFabiano Rosas 
3802f0984d40SFabiano Rosas     tcg_gen_shli_vec(vece, t, a, sh);
3803f0984d40SFabiano Rosas     tcg_gen_dupi_vec(vece, m, MAKE_64BIT_MASK(0, sh));
3804f0984d40SFabiano Rosas     tcg_gen_and_vec(vece, d, d, m);
3805f0984d40SFabiano Rosas     tcg_gen_or_vec(vece, d, d, t);
3806f0984d40SFabiano Rosas 
3807f0984d40SFabiano Rosas     tcg_temp_free_vec(t);
3808f0984d40SFabiano Rosas     tcg_temp_free_vec(m);
3809f0984d40SFabiano Rosas }
3810f0984d40SFabiano Rosas 
3811f0984d40SFabiano Rosas void gen_gvec_sli(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
3812f0984d40SFabiano Rosas                   int64_t shift, uint32_t opr_sz, uint32_t max_sz)
3813f0984d40SFabiano Rosas {
3814f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = { INDEX_op_shli_vec, 0 };
3815f0984d40SFabiano Rosas     const GVecGen2i ops[4] = {
3816f0984d40SFabiano Rosas         { .fni8 = gen_shl8_ins_i64,
3817f0984d40SFabiano Rosas           .fniv = gen_shl_ins_vec,
3818f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sli_b,
3819f0984d40SFabiano Rosas           .load_dest = true,
3820f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3821f0984d40SFabiano Rosas           .vece = MO_8 },
3822f0984d40SFabiano Rosas         { .fni8 = gen_shl16_ins_i64,
3823f0984d40SFabiano Rosas           .fniv = gen_shl_ins_vec,
3824f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sli_h,
3825f0984d40SFabiano Rosas           .load_dest = true,
3826f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3827f0984d40SFabiano Rosas           .vece = MO_16 },
3828f0984d40SFabiano Rosas         { .fni4 = gen_shl32_ins_i32,
3829f0984d40SFabiano Rosas           .fniv = gen_shl_ins_vec,
3830f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sli_s,
3831f0984d40SFabiano Rosas           .load_dest = true,
3832f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3833f0984d40SFabiano Rosas           .vece = MO_32 },
3834f0984d40SFabiano Rosas         { .fni8 = gen_shl64_ins_i64,
3835f0984d40SFabiano Rosas           .fniv = gen_shl_ins_vec,
3836f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sli_d,
3837f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
3838f0984d40SFabiano Rosas           .load_dest = true,
3839f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3840f0984d40SFabiano Rosas           .vece = MO_64 },
3841f0984d40SFabiano Rosas     };
3842f0984d40SFabiano Rosas 
3843f0984d40SFabiano Rosas     /* tszimm encoding produces immediates in the range [0..esize-1]. */
3844f0984d40SFabiano Rosas     tcg_debug_assert(shift >= 0);
3845f0984d40SFabiano Rosas     tcg_debug_assert(shift < (8 << vece));
3846f0984d40SFabiano Rosas 
3847f0984d40SFabiano Rosas     if (shift == 0) {
3848f0984d40SFabiano Rosas         tcg_gen_gvec_mov(vece, rd_ofs, rm_ofs, opr_sz, max_sz);
3849f0984d40SFabiano Rosas     } else {
3850f0984d40SFabiano Rosas         tcg_gen_gvec_2i(rd_ofs, rm_ofs, opr_sz, max_sz, shift, &ops[vece]);
3851f0984d40SFabiano Rosas     }
3852f0984d40SFabiano Rosas }
3853f0984d40SFabiano Rosas 
3854f0984d40SFabiano Rosas static void gen_mla8_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
3855f0984d40SFabiano Rosas {
3856f0984d40SFabiano Rosas     gen_helper_neon_mul_u8(a, a, b);
3857f0984d40SFabiano Rosas     gen_helper_neon_add_u8(d, d, a);
3858f0984d40SFabiano Rosas }
3859f0984d40SFabiano Rosas 
3860f0984d40SFabiano Rosas static void gen_mls8_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
3861f0984d40SFabiano Rosas {
3862f0984d40SFabiano Rosas     gen_helper_neon_mul_u8(a, a, b);
3863f0984d40SFabiano Rosas     gen_helper_neon_sub_u8(d, d, a);
3864f0984d40SFabiano Rosas }
3865f0984d40SFabiano Rosas 
3866f0984d40SFabiano Rosas static void gen_mla16_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
3867f0984d40SFabiano Rosas {
3868f0984d40SFabiano Rosas     gen_helper_neon_mul_u16(a, a, b);
3869f0984d40SFabiano Rosas     gen_helper_neon_add_u16(d, d, a);
3870f0984d40SFabiano Rosas }
3871f0984d40SFabiano Rosas 
3872f0984d40SFabiano Rosas static void gen_mls16_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
3873f0984d40SFabiano Rosas {
3874f0984d40SFabiano Rosas     gen_helper_neon_mul_u16(a, a, b);
3875f0984d40SFabiano Rosas     gen_helper_neon_sub_u16(d, d, a);
3876f0984d40SFabiano Rosas }
3877f0984d40SFabiano Rosas 
3878f0984d40SFabiano Rosas static void gen_mla32_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
3879f0984d40SFabiano Rosas {
3880f0984d40SFabiano Rosas     tcg_gen_mul_i32(a, a, b);
3881f0984d40SFabiano Rosas     tcg_gen_add_i32(d, d, a);
3882f0984d40SFabiano Rosas }
3883f0984d40SFabiano Rosas 
3884f0984d40SFabiano Rosas static void gen_mls32_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
3885f0984d40SFabiano Rosas {
3886f0984d40SFabiano Rosas     tcg_gen_mul_i32(a, a, b);
3887f0984d40SFabiano Rosas     tcg_gen_sub_i32(d, d, a);
3888f0984d40SFabiano Rosas }
3889f0984d40SFabiano Rosas 
3890f0984d40SFabiano Rosas static void gen_mla64_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
3891f0984d40SFabiano Rosas {
3892f0984d40SFabiano Rosas     tcg_gen_mul_i64(a, a, b);
3893f0984d40SFabiano Rosas     tcg_gen_add_i64(d, d, a);
3894f0984d40SFabiano Rosas }
3895f0984d40SFabiano Rosas 
3896f0984d40SFabiano Rosas static void gen_mls64_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
3897f0984d40SFabiano Rosas {
3898f0984d40SFabiano Rosas     tcg_gen_mul_i64(a, a, b);
3899f0984d40SFabiano Rosas     tcg_gen_sub_i64(d, d, a);
3900f0984d40SFabiano Rosas }
3901f0984d40SFabiano Rosas 
3902f0984d40SFabiano Rosas static void gen_mla_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b)
3903f0984d40SFabiano Rosas {
3904f0984d40SFabiano Rosas     tcg_gen_mul_vec(vece, a, a, b);
3905f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, d, d, a);
3906f0984d40SFabiano Rosas }
3907f0984d40SFabiano Rosas 
3908f0984d40SFabiano Rosas static void gen_mls_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b)
3909f0984d40SFabiano Rosas {
3910f0984d40SFabiano Rosas     tcg_gen_mul_vec(vece, a, a, b);
3911f0984d40SFabiano Rosas     tcg_gen_sub_vec(vece, d, d, a);
3912f0984d40SFabiano Rosas }
3913f0984d40SFabiano Rosas 
3914f0984d40SFabiano Rosas /* Note that while NEON does not support VMLA and VMLS as 64-bit ops,
3915f0984d40SFabiano Rosas  * these tables are shared with AArch64 which does support them.
3916f0984d40SFabiano Rosas  */
3917f0984d40SFabiano Rosas void gen_gvec_mla(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
3918f0984d40SFabiano Rosas                   uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
3919f0984d40SFabiano Rosas {
3920f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
3921f0984d40SFabiano Rosas         INDEX_op_mul_vec, INDEX_op_add_vec, 0
3922f0984d40SFabiano Rosas     };
3923f0984d40SFabiano Rosas     static const GVecGen3 ops[4] = {
3924f0984d40SFabiano Rosas         { .fni4 = gen_mla8_i32,
3925f0984d40SFabiano Rosas           .fniv = gen_mla_vec,
3926f0984d40SFabiano Rosas           .load_dest = true,
3927f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3928f0984d40SFabiano Rosas           .vece = MO_8 },
3929f0984d40SFabiano Rosas         { .fni4 = gen_mla16_i32,
3930f0984d40SFabiano Rosas           .fniv = gen_mla_vec,
3931f0984d40SFabiano Rosas           .load_dest = true,
3932f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3933f0984d40SFabiano Rosas           .vece = MO_16 },
3934f0984d40SFabiano Rosas         { .fni4 = gen_mla32_i32,
3935f0984d40SFabiano Rosas           .fniv = gen_mla_vec,
3936f0984d40SFabiano Rosas           .load_dest = true,
3937f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3938f0984d40SFabiano Rosas           .vece = MO_32 },
3939f0984d40SFabiano Rosas         { .fni8 = gen_mla64_i64,
3940f0984d40SFabiano Rosas           .fniv = gen_mla_vec,
3941f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
3942f0984d40SFabiano Rosas           .load_dest = true,
3943f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3944f0984d40SFabiano Rosas           .vece = MO_64 },
3945f0984d40SFabiano Rosas     };
3946f0984d40SFabiano Rosas     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
3947f0984d40SFabiano Rosas }
3948f0984d40SFabiano Rosas 
3949f0984d40SFabiano Rosas void gen_gvec_mls(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
3950f0984d40SFabiano Rosas                   uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
3951f0984d40SFabiano Rosas {
3952f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
3953f0984d40SFabiano Rosas         INDEX_op_mul_vec, INDEX_op_sub_vec, 0
3954f0984d40SFabiano Rosas     };
3955f0984d40SFabiano Rosas     static const GVecGen3 ops[4] = {
3956f0984d40SFabiano Rosas         { .fni4 = gen_mls8_i32,
3957f0984d40SFabiano Rosas           .fniv = gen_mls_vec,
3958f0984d40SFabiano Rosas           .load_dest = true,
3959f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3960f0984d40SFabiano Rosas           .vece = MO_8 },
3961f0984d40SFabiano Rosas         { .fni4 = gen_mls16_i32,
3962f0984d40SFabiano Rosas           .fniv = gen_mls_vec,
3963f0984d40SFabiano Rosas           .load_dest = true,
3964f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3965f0984d40SFabiano Rosas           .vece = MO_16 },
3966f0984d40SFabiano Rosas         { .fni4 = gen_mls32_i32,
3967f0984d40SFabiano Rosas           .fniv = gen_mls_vec,
3968f0984d40SFabiano Rosas           .load_dest = true,
3969f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3970f0984d40SFabiano Rosas           .vece = MO_32 },
3971f0984d40SFabiano Rosas         { .fni8 = gen_mls64_i64,
3972f0984d40SFabiano Rosas           .fniv = gen_mls_vec,
3973f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
3974f0984d40SFabiano Rosas           .load_dest = true,
3975f0984d40SFabiano Rosas           .opt_opc = vecop_list,
3976f0984d40SFabiano Rosas           .vece = MO_64 },
3977f0984d40SFabiano Rosas     };
3978f0984d40SFabiano Rosas     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
3979f0984d40SFabiano Rosas }
3980f0984d40SFabiano Rosas 
3981f0984d40SFabiano Rosas /* CMTST : test is "if (X & Y != 0)". */
3982f0984d40SFabiano Rosas static void gen_cmtst_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
3983f0984d40SFabiano Rosas {
3984f0984d40SFabiano Rosas     tcg_gen_and_i32(d, a, b);
3985f0984d40SFabiano Rosas     tcg_gen_setcondi_i32(TCG_COND_NE, d, d, 0);
3986f0984d40SFabiano Rosas     tcg_gen_neg_i32(d, d);
3987f0984d40SFabiano Rosas }
3988f0984d40SFabiano Rosas 
3989f0984d40SFabiano Rosas void gen_cmtst_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
3990f0984d40SFabiano Rosas {
3991f0984d40SFabiano Rosas     tcg_gen_and_i64(d, a, b);
3992f0984d40SFabiano Rosas     tcg_gen_setcondi_i64(TCG_COND_NE, d, d, 0);
3993f0984d40SFabiano Rosas     tcg_gen_neg_i64(d, d);
3994f0984d40SFabiano Rosas }
3995f0984d40SFabiano Rosas 
3996f0984d40SFabiano Rosas static void gen_cmtst_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b)
3997f0984d40SFabiano Rosas {
3998f0984d40SFabiano Rosas     tcg_gen_and_vec(vece, d, a, b);
3999f0984d40SFabiano Rosas     tcg_gen_dupi_vec(vece, a, 0);
4000f0984d40SFabiano Rosas     tcg_gen_cmp_vec(TCG_COND_NE, vece, d, d, a);
4001f0984d40SFabiano Rosas }
4002f0984d40SFabiano Rosas 
4003f0984d40SFabiano Rosas void gen_gvec_cmtst(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4004f0984d40SFabiano Rosas                     uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4005f0984d40SFabiano Rosas {
4006f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = { INDEX_op_cmp_vec, 0 };
4007f0984d40SFabiano Rosas     static const GVecGen3 ops[4] = {
4008f0984d40SFabiano Rosas         { .fni4 = gen_helper_neon_tst_u8,
4009f0984d40SFabiano Rosas           .fniv = gen_cmtst_vec,
4010f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4011f0984d40SFabiano Rosas           .vece = MO_8 },
4012f0984d40SFabiano Rosas         { .fni4 = gen_helper_neon_tst_u16,
4013f0984d40SFabiano Rosas           .fniv = gen_cmtst_vec,
4014f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4015f0984d40SFabiano Rosas           .vece = MO_16 },
4016f0984d40SFabiano Rosas         { .fni4 = gen_cmtst_i32,
4017f0984d40SFabiano Rosas           .fniv = gen_cmtst_vec,
4018f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4019f0984d40SFabiano Rosas           .vece = MO_32 },
4020f0984d40SFabiano Rosas         { .fni8 = gen_cmtst_i64,
4021f0984d40SFabiano Rosas           .fniv = gen_cmtst_vec,
4022f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
4023f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4024f0984d40SFabiano Rosas           .vece = MO_64 },
4025f0984d40SFabiano Rosas     };
4026f0984d40SFabiano Rosas     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4027f0984d40SFabiano Rosas }
4028f0984d40SFabiano Rosas 
4029f0984d40SFabiano Rosas void gen_ushl_i32(TCGv_i32 dst, TCGv_i32 src, TCGv_i32 shift)
4030f0984d40SFabiano Rosas {
4031f0984d40SFabiano Rosas     TCGv_i32 lval = tcg_temp_new_i32();
4032f0984d40SFabiano Rosas     TCGv_i32 rval = tcg_temp_new_i32();
4033f0984d40SFabiano Rosas     TCGv_i32 lsh = tcg_temp_new_i32();
4034f0984d40SFabiano Rosas     TCGv_i32 rsh = tcg_temp_new_i32();
4035f0984d40SFabiano Rosas     TCGv_i32 zero = tcg_constant_i32(0);
4036f0984d40SFabiano Rosas     TCGv_i32 max = tcg_constant_i32(32);
4037f0984d40SFabiano Rosas 
4038f0984d40SFabiano Rosas     /*
4039f0984d40SFabiano Rosas      * Rely on the TCG guarantee that out of range shifts produce
4040f0984d40SFabiano Rosas      * unspecified results, not undefined behaviour (i.e. no trap).
4041f0984d40SFabiano Rosas      * Discard out-of-range results after the fact.
4042f0984d40SFabiano Rosas      */
4043f0984d40SFabiano Rosas     tcg_gen_ext8s_i32(lsh, shift);
4044f0984d40SFabiano Rosas     tcg_gen_neg_i32(rsh, lsh);
4045f0984d40SFabiano Rosas     tcg_gen_shl_i32(lval, src, lsh);
4046f0984d40SFabiano Rosas     tcg_gen_shr_i32(rval, src, rsh);
4047f0984d40SFabiano Rosas     tcg_gen_movcond_i32(TCG_COND_LTU, dst, lsh, max, lval, zero);
4048f0984d40SFabiano Rosas     tcg_gen_movcond_i32(TCG_COND_LTU, dst, rsh, max, rval, dst);
4049f0984d40SFabiano Rosas 
4050f0984d40SFabiano Rosas     tcg_temp_free_i32(lval);
4051f0984d40SFabiano Rosas     tcg_temp_free_i32(rval);
4052f0984d40SFabiano Rosas     tcg_temp_free_i32(lsh);
4053f0984d40SFabiano Rosas     tcg_temp_free_i32(rsh);
4054f0984d40SFabiano Rosas }
4055f0984d40SFabiano Rosas 
4056f0984d40SFabiano Rosas void gen_ushl_i64(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 shift)
4057f0984d40SFabiano Rosas {
4058f0984d40SFabiano Rosas     TCGv_i64 lval = tcg_temp_new_i64();
4059f0984d40SFabiano Rosas     TCGv_i64 rval = tcg_temp_new_i64();
4060f0984d40SFabiano Rosas     TCGv_i64 lsh = tcg_temp_new_i64();
4061f0984d40SFabiano Rosas     TCGv_i64 rsh = tcg_temp_new_i64();
4062f0984d40SFabiano Rosas     TCGv_i64 zero = tcg_constant_i64(0);
4063f0984d40SFabiano Rosas     TCGv_i64 max = tcg_constant_i64(64);
4064f0984d40SFabiano Rosas 
4065f0984d40SFabiano Rosas     /*
4066f0984d40SFabiano Rosas      * Rely on the TCG guarantee that out of range shifts produce
4067f0984d40SFabiano Rosas      * unspecified results, not undefined behaviour (i.e. no trap).
4068f0984d40SFabiano Rosas      * Discard out-of-range results after the fact.
4069f0984d40SFabiano Rosas      */
4070f0984d40SFabiano Rosas     tcg_gen_ext8s_i64(lsh, shift);
4071f0984d40SFabiano Rosas     tcg_gen_neg_i64(rsh, lsh);
4072f0984d40SFabiano Rosas     tcg_gen_shl_i64(lval, src, lsh);
4073f0984d40SFabiano Rosas     tcg_gen_shr_i64(rval, src, rsh);
4074f0984d40SFabiano Rosas     tcg_gen_movcond_i64(TCG_COND_LTU, dst, lsh, max, lval, zero);
4075f0984d40SFabiano Rosas     tcg_gen_movcond_i64(TCG_COND_LTU, dst, rsh, max, rval, dst);
4076f0984d40SFabiano Rosas 
4077f0984d40SFabiano Rosas     tcg_temp_free_i64(lval);
4078f0984d40SFabiano Rosas     tcg_temp_free_i64(rval);
4079f0984d40SFabiano Rosas     tcg_temp_free_i64(lsh);
4080f0984d40SFabiano Rosas     tcg_temp_free_i64(rsh);
4081f0984d40SFabiano Rosas }
4082f0984d40SFabiano Rosas 
4083f0984d40SFabiano Rosas static void gen_ushl_vec(unsigned vece, TCGv_vec dst,
4084f0984d40SFabiano Rosas                          TCGv_vec src, TCGv_vec shift)
4085f0984d40SFabiano Rosas {
4086f0984d40SFabiano Rosas     TCGv_vec lval = tcg_temp_new_vec_matching(dst);
4087f0984d40SFabiano Rosas     TCGv_vec rval = tcg_temp_new_vec_matching(dst);
4088f0984d40SFabiano Rosas     TCGv_vec lsh = tcg_temp_new_vec_matching(dst);
4089f0984d40SFabiano Rosas     TCGv_vec rsh = tcg_temp_new_vec_matching(dst);
4090f0984d40SFabiano Rosas     TCGv_vec msk, max;
4091f0984d40SFabiano Rosas 
4092f0984d40SFabiano Rosas     tcg_gen_neg_vec(vece, rsh, shift);
4093f0984d40SFabiano Rosas     if (vece == MO_8) {
4094f0984d40SFabiano Rosas         tcg_gen_mov_vec(lsh, shift);
4095f0984d40SFabiano Rosas     } else {
4096f0984d40SFabiano Rosas         msk = tcg_temp_new_vec_matching(dst);
4097f0984d40SFabiano Rosas         tcg_gen_dupi_vec(vece, msk, 0xff);
4098f0984d40SFabiano Rosas         tcg_gen_and_vec(vece, lsh, shift, msk);
4099f0984d40SFabiano Rosas         tcg_gen_and_vec(vece, rsh, rsh, msk);
4100f0984d40SFabiano Rosas         tcg_temp_free_vec(msk);
4101f0984d40SFabiano Rosas     }
4102f0984d40SFabiano Rosas 
4103f0984d40SFabiano Rosas     /*
4104f0984d40SFabiano Rosas      * Rely on the TCG guarantee that out of range shifts produce
4105f0984d40SFabiano Rosas      * unspecified results, not undefined behaviour (i.e. no trap).
4106f0984d40SFabiano Rosas      * Discard out-of-range results after the fact.
4107f0984d40SFabiano Rosas      */
4108f0984d40SFabiano Rosas     tcg_gen_shlv_vec(vece, lval, src, lsh);
4109f0984d40SFabiano Rosas     tcg_gen_shrv_vec(vece, rval, src, rsh);
4110f0984d40SFabiano Rosas 
4111f0984d40SFabiano Rosas     max = tcg_temp_new_vec_matching(dst);
4112f0984d40SFabiano Rosas     tcg_gen_dupi_vec(vece, max, 8 << vece);
4113f0984d40SFabiano Rosas 
4114f0984d40SFabiano Rosas     /*
4115f0984d40SFabiano Rosas      * The choice of LT (signed) and GEU (unsigned) are biased toward
4116f0984d40SFabiano Rosas      * the instructions of the x86_64 host.  For MO_8, the whole byte
4117f0984d40SFabiano Rosas      * is significant so we must use an unsigned compare; otherwise we
4118f0984d40SFabiano Rosas      * have already masked to a byte and so a signed compare works.
4119f0984d40SFabiano Rosas      * Other tcg hosts have a full set of comparisons and do not care.
4120f0984d40SFabiano Rosas      */
4121f0984d40SFabiano Rosas     if (vece == MO_8) {
4122f0984d40SFabiano Rosas         tcg_gen_cmp_vec(TCG_COND_GEU, vece, lsh, lsh, max);
4123f0984d40SFabiano Rosas         tcg_gen_cmp_vec(TCG_COND_GEU, vece, rsh, rsh, max);
4124f0984d40SFabiano Rosas         tcg_gen_andc_vec(vece, lval, lval, lsh);
4125f0984d40SFabiano Rosas         tcg_gen_andc_vec(vece, rval, rval, rsh);
4126f0984d40SFabiano Rosas     } else {
4127f0984d40SFabiano Rosas         tcg_gen_cmp_vec(TCG_COND_LT, vece, lsh, lsh, max);
4128f0984d40SFabiano Rosas         tcg_gen_cmp_vec(TCG_COND_LT, vece, rsh, rsh, max);
4129f0984d40SFabiano Rosas         tcg_gen_and_vec(vece, lval, lval, lsh);
4130f0984d40SFabiano Rosas         tcg_gen_and_vec(vece, rval, rval, rsh);
4131f0984d40SFabiano Rosas     }
4132f0984d40SFabiano Rosas     tcg_gen_or_vec(vece, dst, lval, rval);
4133f0984d40SFabiano Rosas 
4134f0984d40SFabiano Rosas     tcg_temp_free_vec(max);
4135f0984d40SFabiano Rosas     tcg_temp_free_vec(lval);
4136f0984d40SFabiano Rosas     tcg_temp_free_vec(rval);
4137f0984d40SFabiano Rosas     tcg_temp_free_vec(lsh);
4138f0984d40SFabiano Rosas     tcg_temp_free_vec(rsh);
4139f0984d40SFabiano Rosas }
4140f0984d40SFabiano Rosas 
4141f0984d40SFabiano Rosas void gen_gvec_ushl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4142f0984d40SFabiano Rosas                    uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4143f0984d40SFabiano Rosas {
4144f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
4145f0984d40SFabiano Rosas         INDEX_op_neg_vec, INDEX_op_shlv_vec,
4146f0984d40SFabiano Rosas         INDEX_op_shrv_vec, INDEX_op_cmp_vec, 0
4147f0984d40SFabiano Rosas     };
4148f0984d40SFabiano Rosas     static const GVecGen3 ops[4] = {
4149f0984d40SFabiano Rosas         { .fniv = gen_ushl_vec,
4150f0984d40SFabiano Rosas           .fno = gen_helper_gvec_ushl_b,
4151f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4152f0984d40SFabiano Rosas           .vece = MO_8 },
4153f0984d40SFabiano Rosas         { .fniv = gen_ushl_vec,
4154f0984d40SFabiano Rosas           .fno = gen_helper_gvec_ushl_h,
4155f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4156f0984d40SFabiano Rosas           .vece = MO_16 },
4157f0984d40SFabiano Rosas         { .fni4 = gen_ushl_i32,
4158f0984d40SFabiano Rosas           .fniv = gen_ushl_vec,
4159f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4160f0984d40SFabiano Rosas           .vece = MO_32 },
4161f0984d40SFabiano Rosas         { .fni8 = gen_ushl_i64,
4162f0984d40SFabiano Rosas           .fniv = gen_ushl_vec,
4163f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4164f0984d40SFabiano Rosas           .vece = MO_64 },
4165f0984d40SFabiano Rosas     };
4166f0984d40SFabiano Rosas     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4167f0984d40SFabiano Rosas }
4168f0984d40SFabiano Rosas 
4169f0984d40SFabiano Rosas void gen_sshl_i32(TCGv_i32 dst, TCGv_i32 src, TCGv_i32 shift)
4170f0984d40SFabiano Rosas {
4171f0984d40SFabiano Rosas     TCGv_i32 lval = tcg_temp_new_i32();
4172f0984d40SFabiano Rosas     TCGv_i32 rval = tcg_temp_new_i32();
4173f0984d40SFabiano Rosas     TCGv_i32 lsh = tcg_temp_new_i32();
4174f0984d40SFabiano Rosas     TCGv_i32 rsh = tcg_temp_new_i32();
4175f0984d40SFabiano Rosas     TCGv_i32 zero = tcg_constant_i32(0);
4176f0984d40SFabiano Rosas     TCGv_i32 max = tcg_constant_i32(31);
4177f0984d40SFabiano Rosas 
4178f0984d40SFabiano Rosas     /*
4179f0984d40SFabiano Rosas      * Rely on the TCG guarantee that out of range shifts produce
4180f0984d40SFabiano Rosas      * unspecified results, not undefined behaviour (i.e. no trap).
4181f0984d40SFabiano Rosas      * Discard out-of-range results after the fact.
4182f0984d40SFabiano Rosas      */
4183f0984d40SFabiano Rosas     tcg_gen_ext8s_i32(lsh, shift);
4184f0984d40SFabiano Rosas     tcg_gen_neg_i32(rsh, lsh);
4185f0984d40SFabiano Rosas     tcg_gen_shl_i32(lval, src, lsh);
4186f0984d40SFabiano Rosas     tcg_gen_umin_i32(rsh, rsh, max);
4187f0984d40SFabiano Rosas     tcg_gen_sar_i32(rval, src, rsh);
4188f0984d40SFabiano Rosas     tcg_gen_movcond_i32(TCG_COND_LEU, lval, lsh, max, lval, zero);
4189f0984d40SFabiano Rosas     tcg_gen_movcond_i32(TCG_COND_LT, dst, lsh, zero, rval, lval);
4190f0984d40SFabiano Rosas 
4191f0984d40SFabiano Rosas     tcg_temp_free_i32(lval);
4192f0984d40SFabiano Rosas     tcg_temp_free_i32(rval);
4193f0984d40SFabiano Rosas     tcg_temp_free_i32(lsh);
4194f0984d40SFabiano Rosas     tcg_temp_free_i32(rsh);
4195f0984d40SFabiano Rosas }
4196f0984d40SFabiano Rosas 
4197f0984d40SFabiano Rosas void gen_sshl_i64(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 shift)
4198f0984d40SFabiano Rosas {
4199f0984d40SFabiano Rosas     TCGv_i64 lval = tcg_temp_new_i64();
4200f0984d40SFabiano Rosas     TCGv_i64 rval = tcg_temp_new_i64();
4201f0984d40SFabiano Rosas     TCGv_i64 lsh = tcg_temp_new_i64();
4202f0984d40SFabiano Rosas     TCGv_i64 rsh = tcg_temp_new_i64();
4203f0984d40SFabiano Rosas     TCGv_i64 zero = tcg_constant_i64(0);
4204f0984d40SFabiano Rosas     TCGv_i64 max = tcg_constant_i64(63);
4205f0984d40SFabiano Rosas 
4206f0984d40SFabiano Rosas     /*
4207f0984d40SFabiano Rosas      * Rely on the TCG guarantee that out of range shifts produce
4208f0984d40SFabiano Rosas      * unspecified results, not undefined behaviour (i.e. no trap).
4209f0984d40SFabiano Rosas      * Discard out-of-range results after the fact.
4210f0984d40SFabiano Rosas      */
4211f0984d40SFabiano Rosas     tcg_gen_ext8s_i64(lsh, shift);
4212f0984d40SFabiano Rosas     tcg_gen_neg_i64(rsh, lsh);
4213f0984d40SFabiano Rosas     tcg_gen_shl_i64(lval, src, lsh);
4214f0984d40SFabiano Rosas     tcg_gen_umin_i64(rsh, rsh, max);
4215f0984d40SFabiano Rosas     tcg_gen_sar_i64(rval, src, rsh);
4216f0984d40SFabiano Rosas     tcg_gen_movcond_i64(TCG_COND_LEU, lval, lsh, max, lval, zero);
4217f0984d40SFabiano Rosas     tcg_gen_movcond_i64(TCG_COND_LT, dst, lsh, zero, rval, lval);
4218f0984d40SFabiano Rosas 
4219f0984d40SFabiano Rosas     tcg_temp_free_i64(lval);
4220f0984d40SFabiano Rosas     tcg_temp_free_i64(rval);
4221f0984d40SFabiano Rosas     tcg_temp_free_i64(lsh);
4222f0984d40SFabiano Rosas     tcg_temp_free_i64(rsh);
4223f0984d40SFabiano Rosas }
4224f0984d40SFabiano Rosas 
4225f0984d40SFabiano Rosas static void gen_sshl_vec(unsigned vece, TCGv_vec dst,
4226f0984d40SFabiano Rosas                          TCGv_vec src, TCGv_vec shift)
4227f0984d40SFabiano Rosas {
4228f0984d40SFabiano Rosas     TCGv_vec lval = tcg_temp_new_vec_matching(dst);
4229f0984d40SFabiano Rosas     TCGv_vec rval = tcg_temp_new_vec_matching(dst);
4230f0984d40SFabiano Rosas     TCGv_vec lsh = tcg_temp_new_vec_matching(dst);
4231f0984d40SFabiano Rosas     TCGv_vec rsh = tcg_temp_new_vec_matching(dst);
4232f0984d40SFabiano Rosas     TCGv_vec tmp = tcg_temp_new_vec_matching(dst);
4233f0984d40SFabiano Rosas 
4234f0984d40SFabiano Rosas     /*
4235f0984d40SFabiano Rosas      * Rely on the TCG guarantee that out of range shifts produce
4236f0984d40SFabiano Rosas      * unspecified results, not undefined behaviour (i.e. no trap).
4237f0984d40SFabiano Rosas      * Discard out-of-range results after the fact.
4238f0984d40SFabiano Rosas      */
4239f0984d40SFabiano Rosas     tcg_gen_neg_vec(vece, rsh, shift);
4240f0984d40SFabiano Rosas     if (vece == MO_8) {
4241f0984d40SFabiano Rosas         tcg_gen_mov_vec(lsh, shift);
4242f0984d40SFabiano Rosas     } else {
4243f0984d40SFabiano Rosas         tcg_gen_dupi_vec(vece, tmp, 0xff);
4244f0984d40SFabiano Rosas         tcg_gen_and_vec(vece, lsh, shift, tmp);
4245f0984d40SFabiano Rosas         tcg_gen_and_vec(vece, rsh, rsh, tmp);
4246f0984d40SFabiano Rosas     }
4247f0984d40SFabiano Rosas 
4248f0984d40SFabiano Rosas     /* Bound rsh so out of bound right shift gets -1.  */
4249f0984d40SFabiano Rosas     tcg_gen_dupi_vec(vece, tmp, (8 << vece) - 1);
4250f0984d40SFabiano Rosas     tcg_gen_umin_vec(vece, rsh, rsh, tmp);
4251f0984d40SFabiano Rosas     tcg_gen_cmp_vec(TCG_COND_GT, vece, tmp, lsh, tmp);
4252f0984d40SFabiano Rosas 
4253f0984d40SFabiano Rosas     tcg_gen_shlv_vec(vece, lval, src, lsh);
4254f0984d40SFabiano Rosas     tcg_gen_sarv_vec(vece, rval, src, rsh);
4255f0984d40SFabiano Rosas 
4256f0984d40SFabiano Rosas     /* Select in-bound left shift.  */
4257f0984d40SFabiano Rosas     tcg_gen_andc_vec(vece, lval, lval, tmp);
4258f0984d40SFabiano Rosas 
4259f0984d40SFabiano Rosas     /* Select between left and right shift.  */
4260f0984d40SFabiano Rosas     if (vece == MO_8) {
4261f0984d40SFabiano Rosas         tcg_gen_dupi_vec(vece, tmp, 0);
4262f0984d40SFabiano Rosas         tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, tmp, rval, lval);
4263f0984d40SFabiano Rosas     } else {
4264f0984d40SFabiano Rosas         tcg_gen_dupi_vec(vece, tmp, 0x80);
4265f0984d40SFabiano Rosas         tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, tmp, lval, rval);
4266f0984d40SFabiano Rosas     }
4267f0984d40SFabiano Rosas 
4268f0984d40SFabiano Rosas     tcg_temp_free_vec(lval);
4269f0984d40SFabiano Rosas     tcg_temp_free_vec(rval);
4270f0984d40SFabiano Rosas     tcg_temp_free_vec(lsh);
4271f0984d40SFabiano Rosas     tcg_temp_free_vec(rsh);
4272f0984d40SFabiano Rosas     tcg_temp_free_vec(tmp);
4273f0984d40SFabiano Rosas }
4274f0984d40SFabiano Rosas 
4275f0984d40SFabiano Rosas void gen_gvec_sshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4276f0984d40SFabiano Rosas                    uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4277f0984d40SFabiano Rosas {
4278f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
4279f0984d40SFabiano Rosas         INDEX_op_neg_vec, INDEX_op_umin_vec, INDEX_op_shlv_vec,
4280f0984d40SFabiano Rosas         INDEX_op_sarv_vec, INDEX_op_cmp_vec, INDEX_op_cmpsel_vec, 0
4281f0984d40SFabiano Rosas     };
4282f0984d40SFabiano Rosas     static const GVecGen3 ops[4] = {
4283f0984d40SFabiano Rosas         { .fniv = gen_sshl_vec,
4284f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sshl_b,
4285f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4286f0984d40SFabiano Rosas           .vece = MO_8 },
4287f0984d40SFabiano Rosas         { .fniv = gen_sshl_vec,
4288f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sshl_h,
4289f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4290f0984d40SFabiano Rosas           .vece = MO_16 },
4291f0984d40SFabiano Rosas         { .fni4 = gen_sshl_i32,
4292f0984d40SFabiano Rosas           .fniv = gen_sshl_vec,
4293f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4294f0984d40SFabiano Rosas           .vece = MO_32 },
4295f0984d40SFabiano Rosas         { .fni8 = gen_sshl_i64,
4296f0984d40SFabiano Rosas           .fniv = gen_sshl_vec,
4297f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4298f0984d40SFabiano Rosas           .vece = MO_64 },
4299f0984d40SFabiano Rosas     };
4300f0984d40SFabiano Rosas     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4301f0984d40SFabiano Rosas }
4302f0984d40SFabiano Rosas 
4303f0984d40SFabiano Rosas static void gen_uqadd_vec(unsigned vece, TCGv_vec t, TCGv_vec sat,
4304f0984d40SFabiano Rosas                           TCGv_vec a, TCGv_vec b)
4305f0984d40SFabiano Rosas {
4306f0984d40SFabiano Rosas     TCGv_vec x = tcg_temp_new_vec_matching(t);
4307f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, x, a, b);
4308f0984d40SFabiano Rosas     tcg_gen_usadd_vec(vece, t, a, b);
4309f0984d40SFabiano Rosas     tcg_gen_cmp_vec(TCG_COND_NE, vece, x, x, t);
4310f0984d40SFabiano Rosas     tcg_gen_or_vec(vece, sat, sat, x);
4311f0984d40SFabiano Rosas     tcg_temp_free_vec(x);
4312f0984d40SFabiano Rosas }
4313f0984d40SFabiano Rosas 
4314f0984d40SFabiano Rosas void gen_gvec_uqadd_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4315f0984d40SFabiano Rosas                        uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4316f0984d40SFabiano Rosas {
4317f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
4318f0984d40SFabiano Rosas         INDEX_op_usadd_vec, INDEX_op_cmp_vec, INDEX_op_add_vec, 0
4319f0984d40SFabiano Rosas     };
4320f0984d40SFabiano Rosas     static const GVecGen4 ops[4] = {
4321f0984d40SFabiano Rosas         { .fniv = gen_uqadd_vec,
4322f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uqadd_b,
4323f0984d40SFabiano Rosas           .write_aofs = true,
4324f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4325f0984d40SFabiano Rosas           .vece = MO_8 },
4326f0984d40SFabiano Rosas         { .fniv = gen_uqadd_vec,
4327f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uqadd_h,
4328f0984d40SFabiano Rosas           .write_aofs = true,
4329f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4330f0984d40SFabiano Rosas           .vece = MO_16 },
4331f0984d40SFabiano Rosas         { .fniv = gen_uqadd_vec,
4332f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uqadd_s,
4333f0984d40SFabiano Rosas           .write_aofs = true,
4334f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4335f0984d40SFabiano Rosas           .vece = MO_32 },
4336f0984d40SFabiano Rosas         { .fniv = gen_uqadd_vec,
4337f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uqadd_d,
4338f0984d40SFabiano Rosas           .write_aofs = true,
4339f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4340f0984d40SFabiano Rosas           .vece = MO_64 },
4341f0984d40SFabiano Rosas     };
4342f0984d40SFabiano Rosas     tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc),
4343f0984d40SFabiano Rosas                    rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4344f0984d40SFabiano Rosas }
4345f0984d40SFabiano Rosas 
4346f0984d40SFabiano Rosas static void gen_sqadd_vec(unsigned vece, TCGv_vec t, TCGv_vec sat,
4347f0984d40SFabiano Rosas                           TCGv_vec a, TCGv_vec b)
4348f0984d40SFabiano Rosas {
4349f0984d40SFabiano Rosas     TCGv_vec x = tcg_temp_new_vec_matching(t);
4350f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, x, a, b);
4351f0984d40SFabiano Rosas     tcg_gen_ssadd_vec(vece, t, a, b);
4352f0984d40SFabiano Rosas     tcg_gen_cmp_vec(TCG_COND_NE, vece, x, x, t);
4353f0984d40SFabiano Rosas     tcg_gen_or_vec(vece, sat, sat, x);
4354f0984d40SFabiano Rosas     tcg_temp_free_vec(x);
4355f0984d40SFabiano Rosas }
4356f0984d40SFabiano Rosas 
4357f0984d40SFabiano Rosas void gen_gvec_sqadd_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4358f0984d40SFabiano Rosas                        uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4359f0984d40SFabiano Rosas {
4360f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
4361f0984d40SFabiano Rosas         INDEX_op_ssadd_vec, INDEX_op_cmp_vec, INDEX_op_add_vec, 0
4362f0984d40SFabiano Rosas     };
4363f0984d40SFabiano Rosas     static const GVecGen4 ops[4] = {
4364f0984d40SFabiano Rosas         { .fniv = gen_sqadd_vec,
4365f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sqadd_b,
4366f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4367f0984d40SFabiano Rosas           .write_aofs = true,
4368f0984d40SFabiano Rosas           .vece = MO_8 },
4369f0984d40SFabiano Rosas         { .fniv = gen_sqadd_vec,
4370f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sqadd_h,
4371f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4372f0984d40SFabiano Rosas           .write_aofs = true,
4373f0984d40SFabiano Rosas           .vece = MO_16 },
4374f0984d40SFabiano Rosas         { .fniv = gen_sqadd_vec,
4375f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sqadd_s,
4376f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4377f0984d40SFabiano Rosas           .write_aofs = true,
4378f0984d40SFabiano Rosas           .vece = MO_32 },
4379f0984d40SFabiano Rosas         { .fniv = gen_sqadd_vec,
4380f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sqadd_d,
4381f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4382f0984d40SFabiano Rosas           .write_aofs = true,
4383f0984d40SFabiano Rosas           .vece = MO_64 },
4384f0984d40SFabiano Rosas     };
4385f0984d40SFabiano Rosas     tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc),
4386f0984d40SFabiano Rosas                    rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4387f0984d40SFabiano Rosas }
4388f0984d40SFabiano Rosas 
4389f0984d40SFabiano Rosas static void gen_uqsub_vec(unsigned vece, TCGv_vec t, TCGv_vec sat,
4390f0984d40SFabiano Rosas                           TCGv_vec a, TCGv_vec b)
4391f0984d40SFabiano Rosas {
4392f0984d40SFabiano Rosas     TCGv_vec x = tcg_temp_new_vec_matching(t);
4393f0984d40SFabiano Rosas     tcg_gen_sub_vec(vece, x, a, b);
4394f0984d40SFabiano Rosas     tcg_gen_ussub_vec(vece, t, a, b);
4395f0984d40SFabiano Rosas     tcg_gen_cmp_vec(TCG_COND_NE, vece, x, x, t);
4396f0984d40SFabiano Rosas     tcg_gen_or_vec(vece, sat, sat, x);
4397f0984d40SFabiano Rosas     tcg_temp_free_vec(x);
4398f0984d40SFabiano Rosas }
4399f0984d40SFabiano Rosas 
4400f0984d40SFabiano Rosas void gen_gvec_uqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4401f0984d40SFabiano Rosas                        uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4402f0984d40SFabiano Rosas {
4403f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
4404f0984d40SFabiano Rosas         INDEX_op_ussub_vec, INDEX_op_cmp_vec, INDEX_op_sub_vec, 0
4405f0984d40SFabiano Rosas     };
4406f0984d40SFabiano Rosas     static const GVecGen4 ops[4] = {
4407f0984d40SFabiano Rosas         { .fniv = gen_uqsub_vec,
4408f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uqsub_b,
4409f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4410f0984d40SFabiano Rosas           .write_aofs = true,
4411f0984d40SFabiano Rosas           .vece = MO_8 },
4412f0984d40SFabiano Rosas         { .fniv = gen_uqsub_vec,
4413f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uqsub_h,
4414f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4415f0984d40SFabiano Rosas           .write_aofs = true,
4416f0984d40SFabiano Rosas           .vece = MO_16 },
4417f0984d40SFabiano Rosas         { .fniv = gen_uqsub_vec,
4418f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uqsub_s,
4419f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4420f0984d40SFabiano Rosas           .write_aofs = true,
4421f0984d40SFabiano Rosas           .vece = MO_32 },
4422f0984d40SFabiano Rosas         { .fniv = gen_uqsub_vec,
4423f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uqsub_d,
4424f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4425f0984d40SFabiano Rosas           .write_aofs = true,
4426f0984d40SFabiano Rosas           .vece = MO_64 },
4427f0984d40SFabiano Rosas     };
4428f0984d40SFabiano Rosas     tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc),
4429f0984d40SFabiano Rosas                    rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4430f0984d40SFabiano Rosas }
4431f0984d40SFabiano Rosas 
4432f0984d40SFabiano Rosas static void gen_sqsub_vec(unsigned vece, TCGv_vec t, TCGv_vec sat,
4433f0984d40SFabiano Rosas                           TCGv_vec a, TCGv_vec b)
4434f0984d40SFabiano Rosas {
4435f0984d40SFabiano Rosas     TCGv_vec x = tcg_temp_new_vec_matching(t);
4436f0984d40SFabiano Rosas     tcg_gen_sub_vec(vece, x, a, b);
4437f0984d40SFabiano Rosas     tcg_gen_sssub_vec(vece, t, a, b);
4438f0984d40SFabiano Rosas     tcg_gen_cmp_vec(TCG_COND_NE, vece, x, x, t);
4439f0984d40SFabiano Rosas     tcg_gen_or_vec(vece, sat, sat, x);
4440f0984d40SFabiano Rosas     tcg_temp_free_vec(x);
4441f0984d40SFabiano Rosas }
4442f0984d40SFabiano Rosas 
4443f0984d40SFabiano Rosas void gen_gvec_sqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4444f0984d40SFabiano Rosas                        uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4445f0984d40SFabiano Rosas {
4446f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
4447f0984d40SFabiano Rosas         INDEX_op_sssub_vec, INDEX_op_cmp_vec, INDEX_op_sub_vec, 0
4448f0984d40SFabiano Rosas     };
4449f0984d40SFabiano Rosas     static const GVecGen4 ops[4] = {
4450f0984d40SFabiano Rosas         { .fniv = gen_sqsub_vec,
4451f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sqsub_b,
4452f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4453f0984d40SFabiano Rosas           .write_aofs = true,
4454f0984d40SFabiano Rosas           .vece = MO_8 },
4455f0984d40SFabiano Rosas         { .fniv = gen_sqsub_vec,
4456f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sqsub_h,
4457f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4458f0984d40SFabiano Rosas           .write_aofs = true,
4459f0984d40SFabiano Rosas           .vece = MO_16 },
4460f0984d40SFabiano Rosas         { .fniv = gen_sqsub_vec,
4461f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sqsub_s,
4462f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4463f0984d40SFabiano Rosas           .write_aofs = true,
4464f0984d40SFabiano Rosas           .vece = MO_32 },
4465f0984d40SFabiano Rosas         { .fniv = gen_sqsub_vec,
4466f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sqsub_d,
4467f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4468f0984d40SFabiano Rosas           .write_aofs = true,
4469f0984d40SFabiano Rosas           .vece = MO_64 },
4470f0984d40SFabiano Rosas     };
4471f0984d40SFabiano Rosas     tcg_gen_gvec_4(rd_ofs, offsetof(CPUARMState, vfp.qc),
4472f0984d40SFabiano Rosas                    rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4473f0984d40SFabiano Rosas }
4474f0984d40SFabiano Rosas 
4475f0984d40SFabiano Rosas static void gen_sabd_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
4476f0984d40SFabiano Rosas {
4477f0984d40SFabiano Rosas     TCGv_i32 t = tcg_temp_new_i32();
4478f0984d40SFabiano Rosas 
4479f0984d40SFabiano Rosas     tcg_gen_sub_i32(t, a, b);
4480f0984d40SFabiano Rosas     tcg_gen_sub_i32(d, b, a);
4481f0984d40SFabiano Rosas     tcg_gen_movcond_i32(TCG_COND_LT, d, a, b, d, t);
4482f0984d40SFabiano Rosas     tcg_temp_free_i32(t);
4483f0984d40SFabiano Rosas }
4484f0984d40SFabiano Rosas 
4485f0984d40SFabiano Rosas static void gen_sabd_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
4486f0984d40SFabiano Rosas {
4487f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
4488f0984d40SFabiano Rosas 
4489f0984d40SFabiano Rosas     tcg_gen_sub_i64(t, a, b);
4490f0984d40SFabiano Rosas     tcg_gen_sub_i64(d, b, a);
4491f0984d40SFabiano Rosas     tcg_gen_movcond_i64(TCG_COND_LT, d, a, b, d, t);
4492f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
4493f0984d40SFabiano Rosas }
4494f0984d40SFabiano Rosas 
4495f0984d40SFabiano Rosas static void gen_sabd_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b)
4496f0984d40SFabiano Rosas {
4497f0984d40SFabiano Rosas     TCGv_vec t = tcg_temp_new_vec_matching(d);
4498f0984d40SFabiano Rosas 
4499f0984d40SFabiano Rosas     tcg_gen_smin_vec(vece, t, a, b);
4500f0984d40SFabiano Rosas     tcg_gen_smax_vec(vece, d, a, b);
4501f0984d40SFabiano Rosas     tcg_gen_sub_vec(vece, d, d, t);
4502f0984d40SFabiano Rosas     tcg_temp_free_vec(t);
4503f0984d40SFabiano Rosas }
4504f0984d40SFabiano Rosas 
4505f0984d40SFabiano Rosas void gen_gvec_sabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4506f0984d40SFabiano Rosas                    uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4507f0984d40SFabiano Rosas {
4508f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
4509f0984d40SFabiano Rosas         INDEX_op_sub_vec, INDEX_op_smin_vec, INDEX_op_smax_vec, 0
4510f0984d40SFabiano Rosas     };
4511f0984d40SFabiano Rosas     static const GVecGen3 ops[4] = {
4512f0984d40SFabiano Rosas         { .fniv = gen_sabd_vec,
4513f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sabd_b,
4514f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4515f0984d40SFabiano Rosas           .vece = MO_8 },
4516f0984d40SFabiano Rosas         { .fniv = gen_sabd_vec,
4517f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sabd_h,
4518f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4519f0984d40SFabiano Rosas           .vece = MO_16 },
4520f0984d40SFabiano Rosas         { .fni4 = gen_sabd_i32,
4521f0984d40SFabiano Rosas           .fniv = gen_sabd_vec,
4522f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sabd_s,
4523f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4524f0984d40SFabiano Rosas           .vece = MO_32 },
4525f0984d40SFabiano Rosas         { .fni8 = gen_sabd_i64,
4526f0984d40SFabiano Rosas           .fniv = gen_sabd_vec,
4527f0984d40SFabiano Rosas           .fno = gen_helper_gvec_sabd_d,
4528f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
4529f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4530f0984d40SFabiano Rosas           .vece = MO_64 },
4531f0984d40SFabiano Rosas     };
4532f0984d40SFabiano Rosas     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4533f0984d40SFabiano Rosas }
4534f0984d40SFabiano Rosas 
4535f0984d40SFabiano Rosas static void gen_uabd_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
4536f0984d40SFabiano Rosas {
4537f0984d40SFabiano Rosas     TCGv_i32 t = tcg_temp_new_i32();
4538f0984d40SFabiano Rosas 
4539f0984d40SFabiano Rosas     tcg_gen_sub_i32(t, a, b);
4540f0984d40SFabiano Rosas     tcg_gen_sub_i32(d, b, a);
4541f0984d40SFabiano Rosas     tcg_gen_movcond_i32(TCG_COND_LTU, d, a, b, d, t);
4542f0984d40SFabiano Rosas     tcg_temp_free_i32(t);
4543f0984d40SFabiano Rosas }
4544f0984d40SFabiano Rosas 
4545f0984d40SFabiano Rosas static void gen_uabd_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
4546f0984d40SFabiano Rosas {
4547f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
4548f0984d40SFabiano Rosas 
4549f0984d40SFabiano Rosas     tcg_gen_sub_i64(t, a, b);
4550f0984d40SFabiano Rosas     tcg_gen_sub_i64(d, b, a);
4551f0984d40SFabiano Rosas     tcg_gen_movcond_i64(TCG_COND_LTU, d, a, b, d, t);
4552f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
4553f0984d40SFabiano Rosas }
4554f0984d40SFabiano Rosas 
4555f0984d40SFabiano Rosas static void gen_uabd_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b)
4556f0984d40SFabiano Rosas {
4557f0984d40SFabiano Rosas     TCGv_vec t = tcg_temp_new_vec_matching(d);
4558f0984d40SFabiano Rosas 
4559f0984d40SFabiano Rosas     tcg_gen_umin_vec(vece, t, a, b);
4560f0984d40SFabiano Rosas     tcg_gen_umax_vec(vece, d, a, b);
4561f0984d40SFabiano Rosas     tcg_gen_sub_vec(vece, d, d, t);
4562f0984d40SFabiano Rosas     tcg_temp_free_vec(t);
4563f0984d40SFabiano Rosas }
4564f0984d40SFabiano Rosas 
4565f0984d40SFabiano Rosas void gen_gvec_uabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4566f0984d40SFabiano Rosas                    uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4567f0984d40SFabiano Rosas {
4568f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
4569f0984d40SFabiano Rosas         INDEX_op_sub_vec, INDEX_op_umin_vec, INDEX_op_umax_vec, 0
4570f0984d40SFabiano Rosas     };
4571f0984d40SFabiano Rosas     static const GVecGen3 ops[4] = {
4572f0984d40SFabiano Rosas         { .fniv = gen_uabd_vec,
4573f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uabd_b,
4574f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4575f0984d40SFabiano Rosas           .vece = MO_8 },
4576f0984d40SFabiano Rosas         { .fniv = gen_uabd_vec,
4577f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uabd_h,
4578f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4579f0984d40SFabiano Rosas           .vece = MO_16 },
4580f0984d40SFabiano Rosas         { .fni4 = gen_uabd_i32,
4581f0984d40SFabiano Rosas           .fniv = gen_uabd_vec,
4582f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uabd_s,
4583f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4584f0984d40SFabiano Rosas           .vece = MO_32 },
4585f0984d40SFabiano Rosas         { .fni8 = gen_uabd_i64,
4586f0984d40SFabiano Rosas           .fniv = gen_uabd_vec,
4587f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uabd_d,
4588f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
4589f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4590f0984d40SFabiano Rosas           .vece = MO_64 },
4591f0984d40SFabiano Rosas     };
4592f0984d40SFabiano Rosas     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4593f0984d40SFabiano Rosas }
4594f0984d40SFabiano Rosas 
4595f0984d40SFabiano Rosas static void gen_saba_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
4596f0984d40SFabiano Rosas {
4597f0984d40SFabiano Rosas     TCGv_i32 t = tcg_temp_new_i32();
4598f0984d40SFabiano Rosas     gen_sabd_i32(t, a, b);
4599f0984d40SFabiano Rosas     tcg_gen_add_i32(d, d, t);
4600f0984d40SFabiano Rosas     tcg_temp_free_i32(t);
4601f0984d40SFabiano Rosas }
4602f0984d40SFabiano Rosas 
4603f0984d40SFabiano Rosas static void gen_saba_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
4604f0984d40SFabiano Rosas {
4605f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
4606f0984d40SFabiano Rosas     gen_sabd_i64(t, a, b);
4607f0984d40SFabiano Rosas     tcg_gen_add_i64(d, d, t);
4608f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
4609f0984d40SFabiano Rosas }
4610f0984d40SFabiano Rosas 
4611f0984d40SFabiano Rosas static void gen_saba_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b)
4612f0984d40SFabiano Rosas {
4613f0984d40SFabiano Rosas     TCGv_vec t = tcg_temp_new_vec_matching(d);
4614f0984d40SFabiano Rosas     gen_sabd_vec(vece, t, a, b);
4615f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, d, d, t);
4616f0984d40SFabiano Rosas     tcg_temp_free_vec(t);
4617f0984d40SFabiano Rosas }
4618f0984d40SFabiano Rosas 
4619f0984d40SFabiano Rosas void gen_gvec_saba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4620f0984d40SFabiano Rosas                    uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4621f0984d40SFabiano Rosas {
4622f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
4623f0984d40SFabiano Rosas         INDEX_op_sub_vec, INDEX_op_add_vec,
4624f0984d40SFabiano Rosas         INDEX_op_smin_vec, INDEX_op_smax_vec, 0
4625f0984d40SFabiano Rosas     };
4626f0984d40SFabiano Rosas     static const GVecGen3 ops[4] = {
4627f0984d40SFabiano Rosas         { .fniv = gen_saba_vec,
4628f0984d40SFabiano Rosas           .fno = gen_helper_gvec_saba_b,
4629f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4630f0984d40SFabiano Rosas           .load_dest = true,
4631f0984d40SFabiano Rosas           .vece = MO_8 },
4632f0984d40SFabiano Rosas         { .fniv = gen_saba_vec,
4633f0984d40SFabiano Rosas           .fno = gen_helper_gvec_saba_h,
4634f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4635f0984d40SFabiano Rosas           .load_dest = true,
4636f0984d40SFabiano Rosas           .vece = MO_16 },
4637f0984d40SFabiano Rosas         { .fni4 = gen_saba_i32,
4638f0984d40SFabiano Rosas           .fniv = gen_saba_vec,
4639f0984d40SFabiano Rosas           .fno = gen_helper_gvec_saba_s,
4640f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4641f0984d40SFabiano Rosas           .load_dest = true,
4642f0984d40SFabiano Rosas           .vece = MO_32 },
4643f0984d40SFabiano Rosas         { .fni8 = gen_saba_i64,
4644f0984d40SFabiano Rosas           .fniv = gen_saba_vec,
4645f0984d40SFabiano Rosas           .fno = gen_helper_gvec_saba_d,
4646f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
4647f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4648f0984d40SFabiano Rosas           .load_dest = true,
4649f0984d40SFabiano Rosas           .vece = MO_64 },
4650f0984d40SFabiano Rosas     };
4651f0984d40SFabiano Rosas     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4652f0984d40SFabiano Rosas }
4653f0984d40SFabiano Rosas 
4654f0984d40SFabiano Rosas static void gen_uaba_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
4655f0984d40SFabiano Rosas {
4656f0984d40SFabiano Rosas     TCGv_i32 t = tcg_temp_new_i32();
4657f0984d40SFabiano Rosas     gen_uabd_i32(t, a, b);
4658f0984d40SFabiano Rosas     tcg_gen_add_i32(d, d, t);
4659f0984d40SFabiano Rosas     tcg_temp_free_i32(t);
4660f0984d40SFabiano Rosas }
4661f0984d40SFabiano Rosas 
4662f0984d40SFabiano Rosas static void gen_uaba_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
4663f0984d40SFabiano Rosas {
4664f0984d40SFabiano Rosas     TCGv_i64 t = tcg_temp_new_i64();
4665f0984d40SFabiano Rosas     gen_uabd_i64(t, a, b);
4666f0984d40SFabiano Rosas     tcg_gen_add_i64(d, d, t);
4667f0984d40SFabiano Rosas     tcg_temp_free_i64(t);
4668f0984d40SFabiano Rosas }
4669f0984d40SFabiano Rosas 
4670f0984d40SFabiano Rosas static void gen_uaba_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b)
4671f0984d40SFabiano Rosas {
4672f0984d40SFabiano Rosas     TCGv_vec t = tcg_temp_new_vec_matching(d);
4673f0984d40SFabiano Rosas     gen_uabd_vec(vece, t, a, b);
4674f0984d40SFabiano Rosas     tcg_gen_add_vec(vece, d, d, t);
4675f0984d40SFabiano Rosas     tcg_temp_free_vec(t);
4676f0984d40SFabiano Rosas }
4677f0984d40SFabiano Rosas 
4678f0984d40SFabiano Rosas void gen_gvec_uaba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
4679f0984d40SFabiano Rosas                    uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
4680f0984d40SFabiano Rosas {
4681f0984d40SFabiano Rosas     static const TCGOpcode vecop_list[] = {
4682f0984d40SFabiano Rosas         INDEX_op_sub_vec, INDEX_op_add_vec,
4683f0984d40SFabiano Rosas         INDEX_op_umin_vec, INDEX_op_umax_vec, 0
4684f0984d40SFabiano Rosas     };
4685f0984d40SFabiano Rosas     static const GVecGen3 ops[4] = {
4686f0984d40SFabiano Rosas         { .fniv = gen_uaba_vec,
4687f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uaba_b,
4688f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4689f0984d40SFabiano Rosas           .load_dest = true,
4690f0984d40SFabiano Rosas           .vece = MO_8 },
4691f0984d40SFabiano Rosas         { .fniv = gen_uaba_vec,
4692f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uaba_h,
4693f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4694f0984d40SFabiano Rosas           .load_dest = true,
4695f0984d40SFabiano Rosas           .vece = MO_16 },
4696f0984d40SFabiano Rosas         { .fni4 = gen_uaba_i32,
4697f0984d40SFabiano Rosas           .fniv = gen_uaba_vec,
4698f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uaba_s,
4699f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4700f0984d40SFabiano Rosas           .load_dest = true,
4701f0984d40SFabiano Rosas           .vece = MO_32 },
4702f0984d40SFabiano Rosas         { .fni8 = gen_uaba_i64,
4703f0984d40SFabiano Rosas           .fniv = gen_uaba_vec,
4704f0984d40SFabiano Rosas           .fno = gen_helper_gvec_uaba_d,
4705f0984d40SFabiano Rosas           .prefer_i64 = TCG_TARGET_REG_BITS == 64,
4706f0984d40SFabiano Rosas           .opt_opc = vecop_list,
4707f0984d40SFabiano Rosas           .load_dest = true,
4708f0984d40SFabiano Rosas           .vece = MO_64 },
4709f0984d40SFabiano Rosas     };
4710f0984d40SFabiano Rosas     tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
4711f0984d40SFabiano Rosas }
4712f0984d40SFabiano Rosas 
4713f0984d40SFabiano Rosas static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
4714f0984d40SFabiano Rosas                            int opc1, int crn, int crm, int opc2,
4715f0984d40SFabiano Rosas                            bool isread, int rt, int rt2)
4716f0984d40SFabiano Rosas {
4717f0984d40SFabiano Rosas     uint32_t key = ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2);
4718f0984d40SFabiano Rosas     const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
4719f0984d40SFabiano Rosas     TCGv_ptr tcg_ri = NULL;
4720f0984d40SFabiano Rosas     bool need_exit_tb;
4721f0984d40SFabiano Rosas     uint32_t syndrome;
4722f0984d40SFabiano Rosas 
4723f0984d40SFabiano Rosas     /*
4724f0984d40SFabiano Rosas      * Note that since we are an implementation which takes an
4725f0984d40SFabiano Rosas      * exception on a trapped conditional instruction only if the
4726f0984d40SFabiano Rosas      * instruction passes its condition code check, we can take
4727f0984d40SFabiano Rosas      * advantage of the clause in the ARM ARM that allows us to set
4728f0984d40SFabiano Rosas      * the COND field in the instruction to 0xE in all cases.
4729f0984d40SFabiano Rosas      * We could fish the actual condition out of the insn (ARM)
4730f0984d40SFabiano Rosas      * or the condexec bits (Thumb) but it isn't necessary.
4731f0984d40SFabiano Rosas      */
4732f0984d40SFabiano Rosas     switch (cpnum) {
4733f0984d40SFabiano Rosas     case 14:
4734f0984d40SFabiano Rosas         if (is64) {
4735f0984d40SFabiano Rosas             syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
4736f0984d40SFabiano Rosas                                          isread, false);
4737f0984d40SFabiano Rosas         } else {
4738f0984d40SFabiano Rosas             syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
4739f0984d40SFabiano Rosas                                         rt, isread, false);
4740f0984d40SFabiano Rosas         }
4741f0984d40SFabiano Rosas         break;
4742f0984d40SFabiano Rosas     case 15:
4743f0984d40SFabiano Rosas         if (is64) {
4744f0984d40SFabiano Rosas             syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
4745f0984d40SFabiano Rosas                                          isread, false);
4746f0984d40SFabiano Rosas         } else {
4747f0984d40SFabiano Rosas             syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
4748f0984d40SFabiano Rosas                                         rt, isread, false);
4749f0984d40SFabiano Rosas         }
4750f0984d40SFabiano Rosas         break;
4751f0984d40SFabiano Rosas     default:
4752f0984d40SFabiano Rosas         /*
4753f0984d40SFabiano Rosas          * ARMv8 defines that only coprocessors 14 and 15 exist,
4754f0984d40SFabiano Rosas          * so this can only happen if this is an ARMv7 or earlier CPU,
4755f0984d40SFabiano Rosas          * in which case the syndrome information won't actually be
4756f0984d40SFabiano Rosas          * guest visible.
4757f0984d40SFabiano Rosas          */
4758f0984d40SFabiano Rosas         assert(!arm_dc_feature(s, ARM_FEATURE_V8));
4759f0984d40SFabiano Rosas         syndrome = syn_uncategorized();
4760f0984d40SFabiano Rosas         break;
4761f0984d40SFabiano Rosas     }
4762f0984d40SFabiano Rosas 
4763f0984d40SFabiano Rosas     if (s->hstr_active && cpnum == 15 && s->current_el == 1) {
4764f0984d40SFabiano Rosas         /*
4765f0984d40SFabiano Rosas          * At EL1, check for a HSTR_EL2 trap, which must take precedence
4766f0984d40SFabiano Rosas          * over the UNDEF for "no such register" or the UNDEF for "access
4767f0984d40SFabiano Rosas          * permissions forbid this EL1 access". HSTR_EL2 traps from EL0
4768f0984d40SFabiano Rosas          * only happen if the cpreg doesn't UNDEF at EL0, so we do those in
4769f0984d40SFabiano Rosas          * access_check_cp_reg(), after the checks for whether the access
4770f0984d40SFabiano Rosas          * configurably trapped to EL1.
4771f0984d40SFabiano Rosas          */
4772f0984d40SFabiano Rosas         uint32_t maskbit = is64 ? crm : crn;
4773f0984d40SFabiano Rosas 
4774f0984d40SFabiano Rosas         if (maskbit != 4 && maskbit != 14) {
4775f0984d40SFabiano Rosas             /* T4 and T14 are RES0 so never cause traps */
4776f0984d40SFabiano Rosas             TCGv_i32 t;
4777f0984d40SFabiano Rosas             DisasLabel over = gen_disas_label(s);
4778f0984d40SFabiano Rosas 
4779f0984d40SFabiano Rosas             t = load_cpu_offset(offsetoflow32(CPUARMState, cp15.hstr_el2));
4780f0984d40SFabiano Rosas             tcg_gen_andi_i32(t, t, 1u << maskbit);
4781f0984d40SFabiano Rosas             tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, over.label);
4782f0984d40SFabiano Rosas             tcg_temp_free_i32(t);
4783f0984d40SFabiano Rosas 
4784f0984d40SFabiano Rosas             gen_exception_insn(s, 0, EXCP_UDEF, syndrome);
4785f0984d40SFabiano Rosas             set_disas_label(s, over);
4786f0984d40SFabiano Rosas         }
4787f0984d40SFabiano Rosas     }
4788f0984d40SFabiano Rosas 
4789f0984d40SFabiano Rosas     if (!ri) {
4790f0984d40SFabiano Rosas         /*
4791f0984d40SFabiano Rosas          * Unknown register; this might be a guest error or a QEMU
4792f0984d40SFabiano Rosas          * unimplemented feature.
4793f0984d40SFabiano Rosas          */
4794f0984d40SFabiano Rosas         if (is64) {
4795f0984d40SFabiano Rosas             qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
4796f0984d40SFabiano Rosas                           "64 bit system register cp:%d opc1: %d crm:%d "
4797f0984d40SFabiano Rosas                           "(%s)\n",
4798f0984d40SFabiano Rosas                           isread ? "read" : "write", cpnum, opc1, crm,
4799f0984d40SFabiano Rosas                           s->ns ? "non-secure" : "secure");
4800f0984d40SFabiano Rosas         } else {
4801f0984d40SFabiano Rosas             qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
4802f0984d40SFabiano Rosas                           "system register cp:%d opc1:%d crn:%d crm:%d "
4803f0984d40SFabiano Rosas                           "opc2:%d (%s)\n",
4804f0984d40SFabiano Rosas                           isread ? "read" : "write", cpnum, opc1, crn,
4805f0984d40SFabiano Rosas                           crm, opc2, s->ns ? "non-secure" : "secure");
4806f0984d40SFabiano Rosas         }
4807f0984d40SFabiano Rosas         unallocated_encoding(s);
4808f0984d40SFabiano Rosas         return;
4809f0984d40SFabiano Rosas     }
4810f0984d40SFabiano Rosas 
4811f0984d40SFabiano Rosas     /* Check access permissions */
4812f0984d40SFabiano Rosas     if (!cp_access_ok(s->current_el, ri, isread)) {
4813f0984d40SFabiano Rosas         unallocated_encoding(s);
4814f0984d40SFabiano Rosas         return;
4815f0984d40SFabiano Rosas     }
4816f0984d40SFabiano Rosas 
4817f0984d40SFabiano Rosas     if ((s->hstr_active && s->current_el == 0) || ri->accessfn ||
4818f0984d40SFabiano Rosas         (ri->fgt && s->fgt_active) ||
4819f0984d40SFabiano Rosas         (arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) {
4820f0984d40SFabiano Rosas         /*
4821f0984d40SFabiano Rosas          * Emit code to perform further access permissions checks at
4822f0984d40SFabiano Rosas          * runtime; this may result in an exception.
4823f0984d40SFabiano Rosas          * Note that on XScale all cp0..c13 registers do an access check
4824f0984d40SFabiano Rosas          * call in order to handle c15_cpar.
4825f0984d40SFabiano Rosas          */
4826f0984d40SFabiano Rosas         gen_set_condexec(s);
4827f0984d40SFabiano Rosas         gen_update_pc(s, 0);
4828f0984d40SFabiano Rosas         tcg_ri = tcg_temp_new_ptr();
4829f0984d40SFabiano Rosas         gen_helper_access_check_cp_reg(tcg_ri, cpu_env,
4830f0984d40SFabiano Rosas                                        tcg_constant_i32(key),
4831f0984d40SFabiano Rosas                                        tcg_constant_i32(syndrome),
4832f0984d40SFabiano Rosas                                        tcg_constant_i32(isread));
4833f0984d40SFabiano Rosas     } else if (ri->type & ARM_CP_RAISES_EXC) {
4834f0984d40SFabiano Rosas         /*
4835f0984d40SFabiano Rosas          * The readfn or writefn might raise an exception;
4836f0984d40SFabiano Rosas          * synchronize the CPU state in case it does.
4837f0984d40SFabiano Rosas          */
4838f0984d40SFabiano Rosas         gen_set_condexec(s);
4839f0984d40SFabiano Rosas         gen_update_pc(s, 0);
4840f0984d40SFabiano Rosas     }
4841f0984d40SFabiano Rosas 
4842f0984d40SFabiano Rosas     /* Handle special cases first */
4843f0984d40SFabiano Rosas     switch (ri->type & ARM_CP_SPECIAL_MASK) {
4844f0984d40SFabiano Rosas     case 0:
4845f0984d40SFabiano Rosas         break;
4846f0984d40SFabiano Rosas     case ARM_CP_NOP:
4847f0984d40SFabiano Rosas         goto exit;
4848f0984d40SFabiano Rosas     case ARM_CP_WFI:
4849f0984d40SFabiano Rosas         if (isread) {
4850f0984d40SFabiano Rosas             unallocated_encoding(s);
4851f0984d40SFabiano Rosas         } else {
4852f0984d40SFabiano Rosas             gen_update_pc(s, curr_insn_len(s));
4853f0984d40SFabiano Rosas             s->base.is_jmp = DISAS_WFI;
4854f0984d40SFabiano Rosas         }
4855f0984d40SFabiano Rosas         goto exit;
4856f0984d40SFabiano Rosas     default:
4857f0984d40SFabiano Rosas         g_assert_not_reached();
4858f0984d40SFabiano Rosas     }
4859f0984d40SFabiano Rosas 
4860f0984d40SFabiano Rosas     if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
4861f0984d40SFabiano Rosas         gen_io_start();
4862f0984d40SFabiano Rosas     }
4863f0984d40SFabiano Rosas 
4864f0984d40SFabiano Rosas     if (isread) {
4865f0984d40SFabiano Rosas         /* Read */
4866f0984d40SFabiano Rosas         if (is64) {
4867f0984d40SFabiano Rosas             TCGv_i64 tmp64;
4868f0984d40SFabiano Rosas             TCGv_i32 tmp;
4869f0984d40SFabiano Rosas             if (ri->type & ARM_CP_CONST) {
4870f0984d40SFabiano Rosas                 tmp64 = tcg_constant_i64(ri->resetvalue);
4871f0984d40SFabiano Rosas             } else if (ri->readfn) {
4872f0984d40SFabiano Rosas                 if (!tcg_ri) {
4873f0984d40SFabiano Rosas                     tcg_ri = gen_lookup_cp_reg(key);
4874f0984d40SFabiano Rosas                 }
4875f0984d40SFabiano Rosas                 tmp64 = tcg_temp_new_i64();
4876f0984d40SFabiano Rosas                 gen_helper_get_cp_reg64(tmp64, cpu_env, tcg_ri);
4877f0984d40SFabiano Rosas             } else {
4878f0984d40SFabiano Rosas                 tmp64 = tcg_temp_new_i64();
4879f0984d40SFabiano Rosas                 tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset);
4880f0984d40SFabiano Rosas             }
4881f0984d40SFabiano Rosas             tmp = tcg_temp_new_i32();
4882f0984d40SFabiano Rosas             tcg_gen_extrl_i64_i32(tmp, tmp64);
4883f0984d40SFabiano Rosas             store_reg(s, rt, tmp);
4884f0984d40SFabiano Rosas             tmp = tcg_temp_new_i32();
4885f0984d40SFabiano Rosas             tcg_gen_extrh_i64_i32(tmp, tmp64);
4886f0984d40SFabiano Rosas             tcg_temp_free_i64(tmp64);
4887f0984d40SFabiano Rosas             store_reg(s, rt2, tmp);
4888f0984d40SFabiano Rosas         } else {
4889f0984d40SFabiano Rosas             TCGv_i32 tmp;
4890f0984d40SFabiano Rosas             if (ri->type & ARM_CP_CONST) {
4891f0984d40SFabiano Rosas                 tmp = tcg_constant_i32(ri->resetvalue);
4892f0984d40SFabiano Rosas             } else if (ri->readfn) {
4893f0984d40SFabiano Rosas                 if (!tcg_ri) {
4894f0984d40SFabiano Rosas                     tcg_ri = gen_lookup_cp_reg(key);
4895f0984d40SFabiano Rosas                 }
4896f0984d40SFabiano Rosas                 tmp = tcg_temp_new_i32();
4897f0984d40SFabiano Rosas                 gen_helper_get_cp_reg(tmp, cpu_env, tcg_ri);
4898f0984d40SFabiano Rosas             } else {
4899f0984d40SFabiano Rosas                 tmp = load_cpu_offset(ri->fieldoffset);
4900f0984d40SFabiano Rosas             }
4901f0984d40SFabiano Rosas             if (rt == 15) {
4902f0984d40SFabiano Rosas                 /* Destination register of r15 for 32 bit loads sets
4903f0984d40SFabiano Rosas                  * the condition codes from the high 4 bits of the value
4904f0984d40SFabiano Rosas                  */
4905f0984d40SFabiano Rosas                 gen_set_nzcv(tmp);
4906f0984d40SFabiano Rosas                 tcg_temp_free_i32(tmp);
4907f0984d40SFabiano Rosas             } else {
4908f0984d40SFabiano Rosas                 store_reg(s, rt, tmp);
4909f0984d40SFabiano Rosas             }
4910f0984d40SFabiano Rosas         }
4911f0984d40SFabiano Rosas     } else {
4912f0984d40SFabiano Rosas         /* Write */
4913f0984d40SFabiano Rosas         if (ri->type & ARM_CP_CONST) {
4914f0984d40SFabiano Rosas             /* If not forbidden by access permissions, treat as WI */
4915f0984d40SFabiano Rosas             goto exit;
4916f0984d40SFabiano Rosas         }
4917f0984d40SFabiano Rosas 
4918f0984d40SFabiano Rosas         if (is64) {
4919f0984d40SFabiano Rosas             TCGv_i32 tmplo, tmphi;
4920f0984d40SFabiano Rosas             TCGv_i64 tmp64 = tcg_temp_new_i64();
4921f0984d40SFabiano Rosas             tmplo = load_reg(s, rt);
4922f0984d40SFabiano Rosas             tmphi = load_reg(s, rt2);
4923f0984d40SFabiano Rosas             tcg_gen_concat_i32_i64(tmp64, tmplo, tmphi);
4924f0984d40SFabiano Rosas             tcg_temp_free_i32(tmplo);
4925f0984d40SFabiano Rosas             tcg_temp_free_i32(tmphi);
4926f0984d40SFabiano Rosas             if (ri->writefn) {
4927f0984d40SFabiano Rosas                 if (!tcg_ri) {
4928f0984d40SFabiano Rosas                     tcg_ri = gen_lookup_cp_reg(key);
4929f0984d40SFabiano Rosas                 }
4930f0984d40SFabiano Rosas                 gen_helper_set_cp_reg64(cpu_env, tcg_ri, tmp64);
4931f0984d40SFabiano Rosas             } else {
4932f0984d40SFabiano Rosas                 tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset);
4933f0984d40SFabiano Rosas             }
4934f0984d40SFabiano Rosas             tcg_temp_free_i64(tmp64);
4935f0984d40SFabiano Rosas         } else {
4936f0984d40SFabiano Rosas             TCGv_i32 tmp = load_reg(s, rt);
4937f0984d40SFabiano Rosas             if (ri->writefn) {
4938f0984d40SFabiano Rosas                 if (!tcg_ri) {
4939f0984d40SFabiano Rosas                     tcg_ri = gen_lookup_cp_reg(key);
4940f0984d40SFabiano Rosas                 }
4941f0984d40SFabiano Rosas                 gen_helper_set_cp_reg(cpu_env, tcg_ri, tmp);
4942f0984d40SFabiano Rosas                 tcg_temp_free_i32(tmp);
4943f0984d40SFabiano Rosas             } else {
4944f0984d40SFabiano Rosas                 store_cpu_offset(tmp, ri->fieldoffset, 4);
4945f0984d40SFabiano Rosas             }
4946f0984d40SFabiano Rosas         }
4947f0984d40SFabiano Rosas     }
4948f0984d40SFabiano Rosas 
4949f0984d40SFabiano Rosas     /* I/O operations must end the TB here (whether read or write) */
4950f0984d40SFabiano Rosas     need_exit_tb = ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) &&
4951f0984d40SFabiano Rosas                     (ri->type & ARM_CP_IO));
4952f0984d40SFabiano Rosas 
4953f0984d40SFabiano Rosas     if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
4954f0984d40SFabiano Rosas         /*
4955f0984d40SFabiano Rosas          * A write to any coprocessor register that ends a TB
4956f0984d40SFabiano Rosas          * must rebuild the hflags for the next TB.
4957f0984d40SFabiano Rosas          */
4958f0984d40SFabiano Rosas         gen_rebuild_hflags(s, ri->type & ARM_CP_NEWEL);
4959f0984d40SFabiano Rosas         /*
4960f0984d40SFabiano Rosas          * We default to ending the TB on a coprocessor register write,
4961f0984d40SFabiano Rosas          * but allow this to be suppressed by the register definition
4962f0984d40SFabiano Rosas          * (usually only necessary to work around guest bugs).
4963f0984d40SFabiano Rosas          */
4964f0984d40SFabiano Rosas         need_exit_tb = true;
4965f0984d40SFabiano Rosas     }
4966f0984d40SFabiano Rosas     if (need_exit_tb) {
4967f0984d40SFabiano Rosas         gen_lookup_tb(s);
4968f0984d40SFabiano Rosas     }
4969f0984d40SFabiano Rosas 
4970f0984d40SFabiano Rosas  exit:
4971f0984d40SFabiano Rosas     if (tcg_ri) {
4972f0984d40SFabiano Rosas         tcg_temp_free_ptr(tcg_ri);
4973f0984d40SFabiano Rosas     }
4974f0984d40SFabiano Rosas }
4975f0984d40SFabiano Rosas 
4976f0984d40SFabiano Rosas /* Decode XScale DSP or iWMMXt insn (in the copro space, cp=0 or 1) */
4977f0984d40SFabiano Rosas static void disas_xscale_insn(DisasContext *s, uint32_t insn)
4978f0984d40SFabiano Rosas {
4979f0984d40SFabiano Rosas     int cpnum = (insn >> 8) & 0xf;
4980f0984d40SFabiano Rosas 
4981f0984d40SFabiano Rosas     if (extract32(s->c15_cpar, cpnum, 1) == 0) {
4982f0984d40SFabiano Rosas         unallocated_encoding(s);
4983f0984d40SFabiano Rosas     } else if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
4984f0984d40SFabiano Rosas         if (disas_iwmmxt_insn(s, insn)) {
4985f0984d40SFabiano Rosas             unallocated_encoding(s);
4986f0984d40SFabiano Rosas         }
4987f0984d40SFabiano Rosas     } else if (arm_dc_feature(s, ARM_FEATURE_XSCALE)) {
4988f0984d40SFabiano Rosas         if (disas_dsp_insn(s, insn)) {
4989f0984d40SFabiano Rosas             unallocated_encoding(s);
4990f0984d40SFabiano Rosas         }
4991f0984d40SFabiano Rosas     }
4992f0984d40SFabiano Rosas }
4993f0984d40SFabiano Rosas 
4994f0984d40SFabiano Rosas /* Store a 64-bit value to a register pair.  Clobbers val.  */
4995f0984d40SFabiano Rosas static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
4996f0984d40SFabiano Rosas {
4997f0984d40SFabiano Rosas     TCGv_i32 tmp;
4998f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
4999f0984d40SFabiano Rosas     tcg_gen_extrl_i64_i32(tmp, val);
5000f0984d40SFabiano Rosas     store_reg(s, rlow, tmp);
5001f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
5002f0984d40SFabiano Rosas     tcg_gen_extrh_i64_i32(tmp, val);
5003f0984d40SFabiano Rosas     store_reg(s, rhigh, tmp);
5004f0984d40SFabiano Rosas }
5005f0984d40SFabiano Rosas 
5006f0984d40SFabiano Rosas /* load and add a 64-bit value from a register pair.  */
5007f0984d40SFabiano Rosas static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
5008f0984d40SFabiano Rosas {
5009f0984d40SFabiano Rosas     TCGv_i64 tmp;
5010f0984d40SFabiano Rosas     TCGv_i32 tmpl;
5011f0984d40SFabiano Rosas     TCGv_i32 tmph;
5012f0984d40SFabiano Rosas 
5013f0984d40SFabiano Rosas     /* Load 64-bit value rd:rn.  */
5014f0984d40SFabiano Rosas     tmpl = load_reg(s, rlow);
5015f0984d40SFabiano Rosas     tmph = load_reg(s, rhigh);
5016f0984d40SFabiano Rosas     tmp = tcg_temp_new_i64();
5017f0984d40SFabiano Rosas     tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
5018f0984d40SFabiano Rosas     tcg_temp_free_i32(tmpl);
5019f0984d40SFabiano Rosas     tcg_temp_free_i32(tmph);
5020f0984d40SFabiano Rosas     tcg_gen_add_i64(val, val, tmp);
5021f0984d40SFabiano Rosas     tcg_temp_free_i64(tmp);
5022f0984d40SFabiano Rosas }
5023f0984d40SFabiano Rosas 
5024f0984d40SFabiano Rosas /* Set N and Z flags from hi|lo.  */
5025f0984d40SFabiano Rosas static void gen_logicq_cc(TCGv_i32 lo, TCGv_i32 hi)
5026f0984d40SFabiano Rosas {
5027f0984d40SFabiano Rosas     tcg_gen_mov_i32(cpu_NF, hi);
5028f0984d40SFabiano Rosas     tcg_gen_or_i32(cpu_ZF, lo, hi);
5029f0984d40SFabiano Rosas }
5030f0984d40SFabiano Rosas 
5031f0984d40SFabiano Rosas /* Load/Store exclusive instructions are implemented by remembering
5032f0984d40SFabiano Rosas    the value/address loaded, and seeing if these are the same
5033f0984d40SFabiano Rosas    when the store is performed.  This should be sufficient to implement
5034f0984d40SFabiano Rosas    the architecturally mandated semantics, and avoids having to monitor
5035f0984d40SFabiano Rosas    regular stores.  The compare vs the remembered value is done during
5036f0984d40SFabiano Rosas    the cmpxchg operation, but we must compare the addresses manually.  */
5037f0984d40SFabiano Rosas static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
5038f0984d40SFabiano Rosas                                TCGv_i32 addr, int size)
5039f0984d40SFabiano Rosas {
5040f0984d40SFabiano Rosas     TCGv_i32 tmp = tcg_temp_new_i32();
5041f0984d40SFabiano Rosas     MemOp opc = size | MO_ALIGN | s->be_data;
5042f0984d40SFabiano Rosas 
5043f0984d40SFabiano Rosas     s->is_ldex = true;
5044f0984d40SFabiano Rosas 
5045f0984d40SFabiano Rosas     if (size == 3) {
5046f0984d40SFabiano Rosas         TCGv_i32 tmp2 = tcg_temp_new_i32();
5047f0984d40SFabiano Rosas         TCGv_i64 t64 = tcg_temp_new_i64();
5048f0984d40SFabiano Rosas 
5049f0984d40SFabiano Rosas         /*
5050f0984d40SFabiano Rosas          * For AArch32, architecturally the 32-bit word at the lowest
5051f0984d40SFabiano Rosas          * address is always Rt and the one at addr+4 is Rt2, even if
5052f0984d40SFabiano Rosas          * the CPU is big-endian. That means we don't want to do a
5053f0984d40SFabiano Rosas          * gen_aa32_ld_i64(), which checks SCTLR_B as if for an
5054f0984d40SFabiano Rosas          * architecturally 64-bit access, but instead do a 64-bit access
5055f0984d40SFabiano Rosas          * using MO_BE if appropriate and then split the two halves.
5056f0984d40SFabiano Rosas          */
5057f0984d40SFabiano Rosas         TCGv taddr = gen_aa32_addr(s, addr, opc);
5058f0984d40SFabiano Rosas 
5059f0984d40SFabiano Rosas         tcg_gen_qemu_ld_i64(t64, taddr, get_mem_index(s), opc);
5060f0984d40SFabiano Rosas         tcg_temp_free(taddr);
5061f0984d40SFabiano Rosas         tcg_gen_mov_i64(cpu_exclusive_val, t64);
5062f0984d40SFabiano Rosas         if (s->be_data == MO_BE) {
5063f0984d40SFabiano Rosas             tcg_gen_extr_i64_i32(tmp2, tmp, t64);
5064f0984d40SFabiano Rosas         } else {
5065f0984d40SFabiano Rosas             tcg_gen_extr_i64_i32(tmp, tmp2, t64);
5066f0984d40SFabiano Rosas         }
5067f0984d40SFabiano Rosas         tcg_temp_free_i64(t64);
5068f0984d40SFabiano Rosas 
5069f0984d40SFabiano Rosas         store_reg(s, rt2, tmp2);
5070f0984d40SFabiano Rosas     } else {
5071f0984d40SFabiano Rosas         gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), opc);
5072f0984d40SFabiano Rosas         tcg_gen_extu_i32_i64(cpu_exclusive_val, tmp);
5073f0984d40SFabiano Rosas     }
5074f0984d40SFabiano Rosas 
5075f0984d40SFabiano Rosas     store_reg(s, rt, tmp);
5076f0984d40SFabiano Rosas     tcg_gen_extu_i32_i64(cpu_exclusive_addr, addr);
5077f0984d40SFabiano Rosas }
5078f0984d40SFabiano Rosas 
5079f0984d40SFabiano Rosas static void gen_clrex(DisasContext *s)
5080f0984d40SFabiano Rosas {
5081f0984d40SFabiano Rosas     tcg_gen_movi_i64(cpu_exclusive_addr, -1);
5082f0984d40SFabiano Rosas }
5083f0984d40SFabiano Rosas 
5084f0984d40SFabiano Rosas static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
5085f0984d40SFabiano Rosas                                 TCGv_i32 addr, int size)
5086f0984d40SFabiano Rosas {
5087f0984d40SFabiano Rosas     TCGv_i32 t0, t1, t2;
5088f0984d40SFabiano Rosas     TCGv_i64 extaddr;
5089f0984d40SFabiano Rosas     TCGv taddr;
5090f0984d40SFabiano Rosas     TCGLabel *done_label;
5091f0984d40SFabiano Rosas     TCGLabel *fail_label;
5092f0984d40SFabiano Rosas     MemOp opc = size | MO_ALIGN | s->be_data;
5093f0984d40SFabiano Rosas 
5094f0984d40SFabiano Rosas     /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) {
5095f0984d40SFabiano Rosas          [addr] = {Rt};
5096f0984d40SFabiano Rosas          {Rd} = 0;
5097f0984d40SFabiano Rosas        } else {
5098f0984d40SFabiano Rosas          {Rd} = 1;
5099f0984d40SFabiano Rosas        } */
5100f0984d40SFabiano Rosas     fail_label = gen_new_label();
5101f0984d40SFabiano Rosas     done_label = gen_new_label();
5102f0984d40SFabiano Rosas     extaddr = tcg_temp_new_i64();
5103f0984d40SFabiano Rosas     tcg_gen_extu_i32_i64(extaddr, addr);
5104f0984d40SFabiano Rosas     tcg_gen_brcond_i64(TCG_COND_NE, extaddr, cpu_exclusive_addr, fail_label);
5105f0984d40SFabiano Rosas     tcg_temp_free_i64(extaddr);
5106f0984d40SFabiano Rosas 
5107f0984d40SFabiano Rosas     taddr = gen_aa32_addr(s, addr, opc);
5108f0984d40SFabiano Rosas     t0 = tcg_temp_new_i32();
5109f0984d40SFabiano Rosas     t1 = load_reg(s, rt);
5110f0984d40SFabiano Rosas     if (size == 3) {
5111f0984d40SFabiano Rosas         TCGv_i64 o64 = tcg_temp_new_i64();
5112f0984d40SFabiano Rosas         TCGv_i64 n64 = tcg_temp_new_i64();
5113f0984d40SFabiano Rosas 
5114f0984d40SFabiano Rosas         t2 = load_reg(s, rt2);
5115f0984d40SFabiano Rosas 
5116f0984d40SFabiano Rosas         /*
5117f0984d40SFabiano Rosas          * For AArch32, architecturally the 32-bit word at the lowest
5118f0984d40SFabiano Rosas          * address is always Rt and the one at addr+4 is Rt2, even if
5119f0984d40SFabiano Rosas          * the CPU is big-endian. Since we're going to treat this as a
5120f0984d40SFabiano Rosas          * single 64-bit BE store, we need to put the two halves in the
5121f0984d40SFabiano Rosas          * opposite order for BE to LE, so that they end up in the right
5122f0984d40SFabiano Rosas          * places.  We don't want gen_aa32_st_i64, because that checks
5123f0984d40SFabiano Rosas          * SCTLR_B as if for an architectural 64-bit access.
5124f0984d40SFabiano Rosas          */
5125f0984d40SFabiano Rosas         if (s->be_data == MO_BE) {
5126f0984d40SFabiano Rosas             tcg_gen_concat_i32_i64(n64, t2, t1);
5127f0984d40SFabiano Rosas         } else {
5128f0984d40SFabiano Rosas             tcg_gen_concat_i32_i64(n64, t1, t2);
5129f0984d40SFabiano Rosas         }
5130f0984d40SFabiano Rosas         tcg_temp_free_i32(t2);
5131f0984d40SFabiano Rosas 
5132f0984d40SFabiano Rosas         tcg_gen_atomic_cmpxchg_i64(o64, taddr, cpu_exclusive_val, n64,
5133f0984d40SFabiano Rosas                                    get_mem_index(s), opc);
5134f0984d40SFabiano Rosas         tcg_temp_free_i64(n64);
5135f0984d40SFabiano Rosas 
5136f0984d40SFabiano Rosas         tcg_gen_setcond_i64(TCG_COND_NE, o64, o64, cpu_exclusive_val);
5137f0984d40SFabiano Rosas         tcg_gen_extrl_i64_i32(t0, o64);
5138f0984d40SFabiano Rosas 
5139f0984d40SFabiano Rosas         tcg_temp_free_i64(o64);
5140f0984d40SFabiano Rosas     } else {
5141f0984d40SFabiano Rosas         t2 = tcg_temp_new_i32();
5142f0984d40SFabiano Rosas         tcg_gen_extrl_i64_i32(t2, cpu_exclusive_val);
5143f0984d40SFabiano Rosas         tcg_gen_atomic_cmpxchg_i32(t0, taddr, t2, t1, get_mem_index(s), opc);
5144f0984d40SFabiano Rosas         tcg_gen_setcond_i32(TCG_COND_NE, t0, t0, t2);
5145f0984d40SFabiano Rosas         tcg_temp_free_i32(t2);
5146f0984d40SFabiano Rosas     }
5147f0984d40SFabiano Rosas     tcg_temp_free_i32(t1);
5148f0984d40SFabiano Rosas     tcg_temp_free(taddr);
5149f0984d40SFabiano Rosas     tcg_gen_mov_i32(cpu_R[rd], t0);
5150f0984d40SFabiano Rosas     tcg_temp_free_i32(t0);
5151f0984d40SFabiano Rosas     tcg_gen_br(done_label);
5152f0984d40SFabiano Rosas 
5153f0984d40SFabiano Rosas     gen_set_label(fail_label);
5154f0984d40SFabiano Rosas     tcg_gen_movi_i32(cpu_R[rd], 1);
5155f0984d40SFabiano Rosas     gen_set_label(done_label);
5156f0984d40SFabiano Rosas     tcg_gen_movi_i64(cpu_exclusive_addr, -1);
5157f0984d40SFabiano Rosas }
5158f0984d40SFabiano Rosas 
5159f0984d40SFabiano Rosas /* gen_srs:
5160f0984d40SFabiano Rosas  * @env: CPUARMState
5161f0984d40SFabiano Rosas  * @s: DisasContext
5162f0984d40SFabiano Rosas  * @mode: mode field from insn (which stack to store to)
5163f0984d40SFabiano Rosas  * @amode: addressing mode (DA/IA/DB/IB), encoded as per P,U bits in ARM insn
5164f0984d40SFabiano Rosas  * @writeback: true if writeback bit set
5165f0984d40SFabiano Rosas  *
5166f0984d40SFabiano Rosas  * Generate code for the SRS (Store Return State) insn.
5167f0984d40SFabiano Rosas  */
5168f0984d40SFabiano Rosas static void gen_srs(DisasContext *s,
5169f0984d40SFabiano Rosas                     uint32_t mode, uint32_t amode, bool writeback)
5170f0984d40SFabiano Rosas {
5171f0984d40SFabiano Rosas     int32_t offset;
5172f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
5173f0984d40SFabiano Rosas     bool undef = false;
5174f0984d40SFabiano Rosas 
5175f0984d40SFabiano Rosas     /* SRS is:
5176f0984d40SFabiano Rosas      * - trapped to EL3 if EL3 is AArch64 and we are at Secure EL1
5177f0984d40SFabiano Rosas      *   and specified mode is monitor mode
5178f0984d40SFabiano Rosas      * - UNDEFINED in Hyp mode
5179f0984d40SFabiano Rosas      * - UNPREDICTABLE in User or System mode
5180f0984d40SFabiano Rosas      * - UNPREDICTABLE if the specified mode is:
5181f0984d40SFabiano Rosas      * -- not implemented
5182f0984d40SFabiano Rosas      * -- not a valid mode number
5183f0984d40SFabiano Rosas      * -- a mode that's at a higher exception level
5184f0984d40SFabiano Rosas      * -- Monitor, if we are Non-secure
5185f0984d40SFabiano Rosas      * For the UNPREDICTABLE cases we choose to UNDEF.
5186f0984d40SFabiano Rosas      */
5187f0984d40SFabiano Rosas     if (s->current_el == 1 && !s->ns && mode == ARM_CPU_MODE_MON) {
5188f0984d40SFabiano Rosas         gen_exception_insn_el(s, 0, EXCP_UDEF, syn_uncategorized(), 3);
5189f0984d40SFabiano Rosas         return;
5190f0984d40SFabiano Rosas     }
5191f0984d40SFabiano Rosas 
5192f0984d40SFabiano Rosas     if (s->current_el == 0 || s->current_el == 2) {
5193f0984d40SFabiano Rosas         undef = true;
5194f0984d40SFabiano Rosas     }
5195f0984d40SFabiano Rosas 
5196f0984d40SFabiano Rosas     switch (mode) {
5197f0984d40SFabiano Rosas     case ARM_CPU_MODE_USR:
5198f0984d40SFabiano Rosas     case ARM_CPU_MODE_FIQ:
5199f0984d40SFabiano Rosas     case ARM_CPU_MODE_IRQ:
5200f0984d40SFabiano Rosas     case ARM_CPU_MODE_SVC:
5201f0984d40SFabiano Rosas     case ARM_CPU_MODE_ABT:
5202f0984d40SFabiano Rosas     case ARM_CPU_MODE_UND:
5203f0984d40SFabiano Rosas     case ARM_CPU_MODE_SYS:
5204f0984d40SFabiano Rosas         break;
5205f0984d40SFabiano Rosas     case ARM_CPU_MODE_HYP:
5206f0984d40SFabiano Rosas         if (s->current_el == 1 || !arm_dc_feature(s, ARM_FEATURE_EL2)) {
5207f0984d40SFabiano Rosas             undef = true;
5208f0984d40SFabiano Rosas         }
5209f0984d40SFabiano Rosas         break;
5210f0984d40SFabiano Rosas     case ARM_CPU_MODE_MON:
5211f0984d40SFabiano Rosas         /* No need to check specifically for "are we non-secure" because
5212f0984d40SFabiano Rosas          * we've already made EL0 UNDEF and handled the trap for S-EL1;
5213f0984d40SFabiano Rosas          * so if this isn't EL3 then we must be non-secure.
5214f0984d40SFabiano Rosas          */
5215f0984d40SFabiano Rosas         if (s->current_el != 3) {
5216f0984d40SFabiano Rosas             undef = true;
5217f0984d40SFabiano Rosas         }
5218f0984d40SFabiano Rosas         break;
5219f0984d40SFabiano Rosas     default:
5220f0984d40SFabiano Rosas         undef = true;
5221f0984d40SFabiano Rosas     }
5222f0984d40SFabiano Rosas 
5223f0984d40SFabiano Rosas     if (undef) {
5224f0984d40SFabiano Rosas         unallocated_encoding(s);
5225f0984d40SFabiano Rosas         return;
5226f0984d40SFabiano Rosas     }
5227f0984d40SFabiano Rosas 
5228f0984d40SFabiano Rosas     addr = tcg_temp_new_i32();
5229f0984d40SFabiano Rosas     /* get_r13_banked() will raise an exception if called from System mode */
5230f0984d40SFabiano Rosas     gen_set_condexec(s);
5231f0984d40SFabiano Rosas     gen_update_pc(s, 0);
5232f0984d40SFabiano Rosas     gen_helper_get_r13_banked(addr, cpu_env, tcg_constant_i32(mode));
5233f0984d40SFabiano Rosas     switch (amode) {
5234f0984d40SFabiano Rosas     case 0: /* DA */
5235f0984d40SFabiano Rosas         offset = -4;
5236f0984d40SFabiano Rosas         break;
5237f0984d40SFabiano Rosas     case 1: /* IA */
5238f0984d40SFabiano Rosas         offset = 0;
5239f0984d40SFabiano Rosas         break;
5240f0984d40SFabiano Rosas     case 2: /* DB */
5241f0984d40SFabiano Rosas         offset = -8;
5242f0984d40SFabiano Rosas         break;
5243f0984d40SFabiano Rosas     case 3: /* IB */
5244f0984d40SFabiano Rosas         offset = 4;
5245f0984d40SFabiano Rosas         break;
5246f0984d40SFabiano Rosas     default:
5247f0984d40SFabiano Rosas         g_assert_not_reached();
5248f0984d40SFabiano Rosas     }
5249f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, offset);
5250f0984d40SFabiano Rosas     tmp = load_reg(s, 14);
5251f0984d40SFabiano Rosas     gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN);
5252f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
5253f0984d40SFabiano Rosas     tmp = load_cpu_field(spsr);
5254f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, 4);
5255f0984d40SFabiano Rosas     gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN);
5256f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
5257f0984d40SFabiano Rosas     if (writeback) {
5258f0984d40SFabiano Rosas         switch (amode) {
5259f0984d40SFabiano Rosas         case 0:
5260f0984d40SFabiano Rosas             offset = -8;
5261f0984d40SFabiano Rosas             break;
5262f0984d40SFabiano Rosas         case 1:
5263f0984d40SFabiano Rosas             offset = 4;
5264f0984d40SFabiano Rosas             break;
5265f0984d40SFabiano Rosas         case 2:
5266f0984d40SFabiano Rosas             offset = -4;
5267f0984d40SFabiano Rosas             break;
5268f0984d40SFabiano Rosas         case 3:
5269f0984d40SFabiano Rosas             offset = 0;
5270f0984d40SFabiano Rosas             break;
5271f0984d40SFabiano Rosas         default:
5272f0984d40SFabiano Rosas             g_assert_not_reached();
5273f0984d40SFabiano Rosas         }
5274f0984d40SFabiano Rosas         tcg_gen_addi_i32(addr, addr, offset);
5275f0984d40SFabiano Rosas         gen_helper_set_r13_banked(cpu_env, tcg_constant_i32(mode), addr);
5276f0984d40SFabiano Rosas     }
5277f0984d40SFabiano Rosas     tcg_temp_free_i32(addr);
5278f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_UPDATE_EXIT;
5279f0984d40SFabiano Rosas }
5280f0984d40SFabiano Rosas 
5281f0984d40SFabiano Rosas /* Skip this instruction if the ARM condition is false */
5282f0984d40SFabiano Rosas static void arm_skip_unless(DisasContext *s, uint32_t cond)
5283f0984d40SFabiano Rosas {
5284f0984d40SFabiano Rosas     arm_gen_condlabel(s);
5285f0984d40SFabiano Rosas     arm_gen_test_cc(cond ^ 1, s->condlabel.label);
5286f0984d40SFabiano Rosas }
5287f0984d40SFabiano Rosas 
5288f0984d40SFabiano Rosas 
5289f0984d40SFabiano Rosas /*
5290f0984d40SFabiano Rosas  * Constant expanders used by T16/T32 decode
5291f0984d40SFabiano Rosas  */
5292f0984d40SFabiano Rosas 
5293f0984d40SFabiano Rosas /* Return only the rotation part of T32ExpandImm.  */
5294f0984d40SFabiano Rosas static int t32_expandimm_rot(DisasContext *s, int x)
5295f0984d40SFabiano Rosas {
5296f0984d40SFabiano Rosas     return x & 0xc00 ? extract32(x, 7, 5) : 0;
5297f0984d40SFabiano Rosas }
5298f0984d40SFabiano Rosas 
5299f0984d40SFabiano Rosas /* Return the unrotated immediate from T32ExpandImm.  */
5300f0984d40SFabiano Rosas static int t32_expandimm_imm(DisasContext *s, int x)
5301f0984d40SFabiano Rosas {
5302f0984d40SFabiano Rosas     int imm = extract32(x, 0, 8);
5303f0984d40SFabiano Rosas 
5304f0984d40SFabiano Rosas     switch (extract32(x, 8, 4)) {
5305f0984d40SFabiano Rosas     case 0: /* XY */
5306f0984d40SFabiano Rosas         /* Nothing to do.  */
5307f0984d40SFabiano Rosas         break;
5308f0984d40SFabiano Rosas     case 1: /* 00XY00XY */
5309f0984d40SFabiano Rosas         imm *= 0x00010001;
5310f0984d40SFabiano Rosas         break;
5311f0984d40SFabiano Rosas     case 2: /* XY00XY00 */
5312f0984d40SFabiano Rosas         imm *= 0x01000100;
5313f0984d40SFabiano Rosas         break;
5314f0984d40SFabiano Rosas     case 3: /* XYXYXYXY */
5315f0984d40SFabiano Rosas         imm *= 0x01010101;
5316f0984d40SFabiano Rosas         break;
5317f0984d40SFabiano Rosas     default:
5318f0984d40SFabiano Rosas         /* Rotated constant.  */
5319f0984d40SFabiano Rosas         imm |= 0x80;
5320f0984d40SFabiano Rosas         break;
5321f0984d40SFabiano Rosas     }
5322f0984d40SFabiano Rosas     return imm;
5323f0984d40SFabiano Rosas }
5324f0984d40SFabiano Rosas 
5325f0984d40SFabiano Rosas static int t32_branch24(DisasContext *s, int x)
5326f0984d40SFabiano Rosas {
5327f0984d40SFabiano Rosas     /* Convert J1:J2 at x[22:21] to I2:I1, which involves I=J^~S.  */
5328f0984d40SFabiano Rosas     x ^= !(x < 0) * (3 << 21);
5329f0984d40SFabiano Rosas     /* Append the final zero.  */
5330f0984d40SFabiano Rosas     return x << 1;
5331f0984d40SFabiano Rosas }
5332f0984d40SFabiano Rosas 
5333f0984d40SFabiano Rosas static int t16_setflags(DisasContext *s)
5334f0984d40SFabiano Rosas {
5335f0984d40SFabiano Rosas     return s->condexec_mask == 0;
5336f0984d40SFabiano Rosas }
5337f0984d40SFabiano Rosas 
5338f0984d40SFabiano Rosas static int t16_push_list(DisasContext *s, int x)
5339f0984d40SFabiano Rosas {
5340f0984d40SFabiano Rosas     return (x & 0xff) | (x & 0x100) << (14 - 8);
5341f0984d40SFabiano Rosas }
5342f0984d40SFabiano Rosas 
5343f0984d40SFabiano Rosas static int t16_pop_list(DisasContext *s, int x)
5344f0984d40SFabiano Rosas {
5345f0984d40SFabiano Rosas     return (x & 0xff) | (x & 0x100) << (15 - 8);
5346f0984d40SFabiano Rosas }
5347f0984d40SFabiano Rosas 
5348f0984d40SFabiano Rosas /*
5349f0984d40SFabiano Rosas  * Include the generated decoders.
5350f0984d40SFabiano Rosas  */
5351f0984d40SFabiano Rosas 
5352f0984d40SFabiano Rosas #include "decode-a32.c.inc"
5353f0984d40SFabiano Rosas #include "decode-a32-uncond.c.inc"
5354f0984d40SFabiano Rosas #include "decode-t32.c.inc"
5355f0984d40SFabiano Rosas #include "decode-t16.c.inc"
5356f0984d40SFabiano Rosas 
5357f0984d40SFabiano Rosas static bool valid_cp(DisasContext *s, int cp)
5358f0984d40SFabiano Rosas {
5359f0984d40SFabiano Rosas     /*
5360f0984d40SFabiano Rosas      * Return true if this coprocessor field indicates something
5361f0984d40SFabiano Rosas      * that's really a possible coprocessor.
5362f0984d40SFabiano Rosas      * For v7 and earlier, coprocessors 8..15 were reserved for Arm use,
5363f0984d40SFabiano Rosas      * and of those only cp14 and cp15 were used for registers.
5364f0984d40SFabiano Rosas      * cp10 and cp11 were used for VFP and Neon, whose decode is
5365f0984d40SFabiano Rosas      * dealt with elsewhere. With the advent of fp16, cp9 is also
5366f0984d40SFabiano Rosas      * now part of VFP.
5367f0984d40SFabiano Rosas      * For v8A and later, the encoding has been tightened so that
5368f0984d40SFabiano Rosas      * only cp14 and cp15 are valid, and other values aren't considered
5369f0984d40SFabiano Rosas      * to be in the coprocessor-instruction space at all. v8M still
5370f0984d40SFabiano Rosas      * permits coprocessors 0..7.
5371f0984d40SFabiano Rosas      * For XScale, we must not decode the XScale cp0, cp1 space as
5372f0984d40SFabiano Rosas      * a standard coprocessor insn, because we want to fall through to
5373f0984d40SFabiano Rosas      * the legacy disas_xscale_insn() decoder after decodetree is done.
5374f0984d40SFabiano Rosas      */
5375f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_XSCALE) && (cp == 0 || cp == 1)) {
5376f0984d40SFabiano Rosas         return false;
5377f0984d40SFabiano Rosas     }
5378f0984d40SFabiano Rosas 
5379f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_V8) &&
5380f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_M)) {
5381f0984d40SFabiano Rosas         return cp >= 14;
5382f0984d40SFabiano Rosas     }
5383f0984d40SFabiano Rosas     return cp < 8 || cp >= 14;
5384f0984d40SFabiano Rosas }
5385f0984d40SFabiano Rosas 
5386f0984d40SFabiano Rosas static bool trans_MCR(DisasContext *s, arg_MCR *a)
5387f0984d40SFabiano Rosas {
5388f0984d40SFabiano Rosas     if (!valid_cp(s, a->cp)) {
5389f0984d40SFabiano Rosas         return false;
5390f0984d40SFabiano Rosas     }
5391f0984d40SFabiano Rosas     do_coproc_insn(s, a->cp, false, a->opc1, a->crn, a->crm, a->opc2,
5392f0984d40SFabiano Rosas                    false, a->rt, 0);
5393f0984d40SFabiano Rosas     return true;
5394f0984d40SFabiano Rosas }
5395f0984d40SFabiano Rosas 
5396f0984d40SFabiano Rosas static bool trans_MRC(DisasContext *s, arg_MRC *a)
5397f0984d40SFabiano Rosas {
5398f0984d40SFabiano Rosas     if (!valid_cp(s, a->cp)) {
5399f0984d40SFabiano Rosas         return false;
5400f0984d40SFabiano Rosas     }
5401f0984d40SFabiano Rosas     do_coproc_insn(s, a->cp, false, a->opc1, a->crn, a->crm, a->opc2,
5402f0984d40SFabiano Rosas                    true, a->rt, 0);
5403f0984d40SFabiano Rosas     return true;
5404f0984d40SFabiano Rosas }
5405f0984d40SFabiano Rosas 
5406f0984d40SFabiano Rosas static bool trans_MCRR(DisasContext *s, arg_MCRR *a)
5407f0984d40SFabiano Rosas {
5408f0984d40SFabiano Rosas     if (!valid_cp(s, a->cp)) {
5409f0984d40SFabiano Rosas         return false;
5410f0984d40SFabiano Rosas     }
5411f0984d40SFabiano Rosas     do_coproc_insn(s, a->cp, true, a->opc1, 0, a->crm, 0,
5412f0984d40SFabiano Rosas                    false, a->rt, a->rt2);
5413f0984d40SFabiano Rosas     return true;
5414f0984d40SFabiano Rosas }
5415f0984d40SFabiano Rosas 
5416f0984d40SFabiano Rosas static bool trans_MRRC(DisasContext *s, arg_MRRC *a)
5417f0984d40SFabiano Rosas {
5418f0984d40SFabiano Rosas     if (!valid_cp(s, a->cp)) {
5419f0984d40SFabiano Rosas         return false;
5420f0984d40SFabiano Rosas     }
5421f0984d40SFabiano Rosas     do_coproc_insn(s, a->cp, true, a->opc1, 0, a->crm, 0,
5422f0984d40SFabiano Rosas                    true, a->rt, a->rt2);
5423f0984d40SFabiano Rosas     return true;
5424f0984d40SFabiano Rosas }
5425f0984d40SFabiano Rosas 
5426f0984d40SFabiano Rosas /* Helpers to swap operands for reverse-subtract.  */
5427f0984d40SFabiano Rosas static void gen_rsb(TCGv_i32 dst, TCGv_i32 a, TCGv_i32 b)
5428f0984d40SFabiano Rosas {
5429f0984d40SFabiano Rosas     tcg_gen_sub_i32(dst, b, a);
5430f0984d40SFabiano Rosas }
5431f0984d40SFabiano Rosas 
5432f0984d40SFabiano Rosas static void gen_rsb_CC(TCGv_i32 dst, TCGv_i32 a, TCGv_i32 b)
5433f0984d40SFabiano Rosas {
5434f0984d40SFabiano Rosas     gen_sub_CC(dst, b, a);
5435f0984d40SFabiano Rosas }
5436f0984d40SFabiano Rosas 
5437f0984d40SFabiano Rosas static void gen_rsc(TCGv_i32 dest, TCGv_i32 a, TCGv_i32 b)
5438f0984d40SFabiano Rosas {
5439f0984d40SFabiano Rosas     gen_sub_carry(dest, b, a);
5440f0984d40SFabiano Rosas }
5441f0984d40SFabiano Rosas 
5442f0984d40SFabiano Rosas static void gen_rsc_CC(TCGv_i32 dest, TCGv_i32 a, TCGv_i32 b)
5443f0984d40SFabiano Rosas {
5444f0984d40SFabiano Rosas     gen_sbc_CC(dest, b, a);
5445f0984d40SFabiano Rosas }
5446f0984d40SFabiano Rosas 
5447f0984d40SFabiano Rosas /*
5448f0984d40SFabiano Rosas  * Helpers for the data processing routines.
5449f0984d40SFabiano Rosas  *
5450f0984d40SFabiano Rosas  * After the computation store the results back.
5451f0984d40SFabiano Rosas  * This may be suppressed altogether (STREG_NONE), require a runtime
5452f0984d40SFabiano Rosas  * check against the stack limits (STREG_SP_CHECK), or generate an
5453f0984d40SFabiano Rosas  * exception return.  Oh, or store into a register.
5454f0984d40SFabiano Rosas  *
5455f0984d40SFabiano Rosas  * Always return true, indicating success for a trans_* function.
5456f0984d40SFabiano Rosas  */
5457f0984d40SFabiano Rosas typedef enum {
5458f0984d40SFabiano Rosas    STREG_NONE,
5459f0984d40SFabiano Rosas    STREG_NORMAL,
5460f0984d40SFabiano Rosas    STREG_SP_CHECK,
5461f0984d40SFabiano Rosas    STREG_EXC_RET,
5462f0984d40SFabiano Rosas } StoreRegKind;
5463f0984d40SFabiano Rosas 
5464f0984d40SFabiano Rosas static bool store_reg_kind(DisasContext *s, int rd,
5465f0984d40SFabiano Rosas                             TCGv_i32 val, StoreRegKind kind)
5466f0984d40SFabiano Rosas {
5467f0984d40SFabiano Rosas     switch (kind) {
5468f0984d40SFabiano Rosas     case STREG_NONE:
5469f0984d40SFabiano Rosas         tcg_temp_free_i32(val);
5470f0984d40SFabiano Rosas         return true;
5471f0984d40SFabiano Rosas     case STREG_NORMAL:
5472f0984d40SFabiano Rosas         /* See ALUWritePC: Interworking only from a32 mode. */
5473f0984d40SFabiano Rosas         if (s->thumb) {
5474f0984d40SFabiano Rosas             store_reg(s, rd, val);
5475f0984d40SFabiano Rosas         } else {
5476f0984d40SFabiano Rosas             store_reg_bx(s, rd, val);
5477f0984d40SFabiano Rosas         }
5478f0984d40SFabiano Rosas         return true;
5479f0984d40SFabiano Rosas     case STREG_SP_CHECK:
5480f0984d40SFabiano Rosas         store_sp_checked(s, val);
5481f0984d40SFabiano Rosas         return true;
5482f0984d40SFabiano Rosas     case STREG_EXC_RET:
5483f0984d40SFabiano Rosas         gen_exception_return(s, val);
5484f0984d40SFabiano Rosas         return true;
5485f0984d40SFabiano Rosas     }
5486f0984d40SFabiano Rosas     g_assert_not_reached();
5487f0984d40SFabiano Rosas }
5488f0984d40SFabiano Rosas 
5489f0984d40SFabiano Rosas /*
5490f0984d40SFabiano Rosas  * Data Processing (register)
5491f0984d40SFabiano Rosas  *
5492f0984d40SFabiano Rosas  * Operate, with set flags, one register source,
5493f0984d40SFabiano Rosas  * one immediate shifted register source, and a destination.
5494f0984d40SFabiano Rosas  */
5495f0984d40SFabiano Rosas static bool op_s_rrr_shi(DisasContext *s, arg_s_rrr_shi *a,
5496f0984d40SFabiano Rosas                          void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32),
5497f0984d40SFabiano Rosas                          int logic_cc, StoreRegKind kind)
5498f0984d40SFabiano Rosas {
5499f0984d40SFabiano Rosas     TCGv_i32 tmp1, tmp2;
5500f0984d40SFabiano Rosas 
5501f0984d40SFabiano Rosas     tmp2 = load_reg(s, a->rm);
5502f0984d40SFabiano Rosas     gen_arm_shift_im(tmp2, a->shty, a->shim, logic_cc);
5503f0984d40SFabiano Rosas     tmp1 = load_reg(s, a->rn);
5504f0984d40SFabiano Rosas 
5505f0984d40SFabiano Rosas     gen(tmp1, tmp1, tmp2);
5506f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp2);
5507f0984d40SFabiano Rosas 
5508f0984d40SFabiano Rosas     if (logic_cc) {
5509f0984d40SFabiano Rosas         gen_logic_CC(tmp1);
5510f0984d40SFabiano Rosas     }
5511f0984d40SFabiano Rosas     return store_reg_kind(s, a->rd, tmp1, kind);
5512f0984d40SFabiano Rosas }
5513f0984d40SFabiano Rosas 
5514f0984d40SFabiano Rosas static bool op_s_rxr_shi(DisasContext *s, arg_s_rrr_shi *a,
5515f0984d40SFabiano Rosas                          void (*gen)(TCGv_i32, TCGv_i32),
5516f0984d40SFabiano Rosas                          int logic_cc, StoreRegKind kind)
5517f0984d40SFabiano Rosas {
5518f0984d40SFabiano Rosas     TCGv_i32 tmp;
5519f0984d40SFabiano Rosas 
5520f0984d40SFabiano Rosas     tmp = load_reg(s, a->rm);
5521f0984d40SFabiano Rosas     gen_arm_shift_im(tmp, a->shty, a->shim, logic_cc);
5522f0984d40SFabiano Rosas 
5523f0984d40SFabiano Rosas     gen(tmp, tmp);
5524f0984d40SFabiano Rosas     if (logic_cc) {
5525f0984d40SFabiano Rosas         gen_logic_CC(tmp);
5526f0984d40SFabiano Rosas     }
5527f0984d40SFabiano Rosas     return store_reg_kind(s, a->rd, tmp, kind);
5528f0984d40SFabiano Rosas }
5529f0984d40SFabiano Rosas 
5530f0984d40SFabiano Rosas /*
5531f0984d40SFabiano Rosas  * Data-processing (register-shifted register)
5532f0984d40SFabiano Rosas  *
5533f0984d40SFabiano Rosas  * Operate, with set flags, one register source,
5534f0984d40SFabiano Rosas  * one register shifted register source, and a destination.
5535f0984d40SFabiano Rosas  */
5536f0984d40SFabiano Rosas static bool op_s_rrr_shr(DisasContext *s, arg_s_rrr_shr *a,
5537f0984d40SFabiano Rosas                          void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32),
5538f0984d40SFabiano Rosas                          int logic_cc, StoreRegKind kind)
5539f0984d40SFabiano Rosas {
5540f0984d40SFabiano Rosas     TCGv_i32 tmp1, tmp2;
5541f0984d40SFabiano Rosas 
5542f0984d40SFabiano Rosas     tmp1 = load_reg(s, a->rs);
5543f0984d40SFabiano Rosas     tmp2 = load_reg(s, a->rm);
5544f0984d40SFabiano Rosas     gen_arm_shift_reg(tmp2, a->shty, tmp1, logic_cc);
5545f0984d40SFabiano Rosas     tmp1 = load_reg(s, a->rn);
5546f0984d40SFabiano Rosas 
5547f0984d40SFabiano Rosas     gen(tmp1, tmp1, tmp2);
5548f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp2);
5549f0984d40SFabiano Rosas 
5550f0984d40SFabiano Rosas     if (logic_cc) {
5551f0984d40SFabiano Rosas         gen_logic_CC(tmp1);
5552f0984d40SFabiano Rosas     }
5553f0984d40SFabiano Rosas     return store_reg_kind(s, a->rd, tmp1, kind);
5554f0984d40SFabiano Rosas }
5555f0984d40SFabiano Rosas 
5556f0984d40SFabiano Rosas static bool op_s_rxr_shr(DisasContext *s, arg_s_rrr_shr *a,
5557f0984d40SFabiano Rosas                          void (*gen)(TCGv_i32, TCGv_i32),
5558f0984d40SFabiano Rosas                          int logic_cc, StoreRegKind kind)
5559f0984d40SFabiano Rosas {
5560f0984d40SFabiano Rosas     TCGv_i32 tmp1, tmp2;
5561f0984d40SFabiano Rosas 
5562f0984d40SFabiano Rosas     tmp1 = load_reg(s, a->rs);
5563f0984d40SFabiano Rosas     tmp2 = load_reg(s, a->rm);
5564f0984d40SFabiano Rosas     gen_arm_shift_reg(tmp2, a->shty, tmp1, logic_cc);
5565f0984d40SFabiano Rosas 
5566f0984d40SFabiano Rosas     gen(tmp2, tmp2);
5567f0984d40SFabiano Rosas     if (logic_cc) {
5568f0984d40SFabiano Rosas         gen_logic_CC(tmp2);
5569f0984d40SFabiano Rosas     }
5570f0984d40SFabiano Rosas     return store_reg_kind(s, a->rd, tmp2, kind);
5571f0984d40SFabiano Rosas }
5572f0984d40SFabiano Rosas 
5573f0984d40SFabiano Rosas /*
5574f0984d40SFabiano Rosas  * Data-processing (immediate)
5575f0984d40SFabiano Rosas  *
5576f0984d40SFabiano Rosas  * Operate, with set flags, one register source,
5577f0984d40SFabiano Rosas  * one rotated immediate, and a destination.
5578f0984d40SFabiano Rosas  *
5579f0984d40SFabiano Rosas  * Note that logic_cc && a->rot setting CF based on the msb of the
5580f0984d40SFabiano Rosas  * immediate is the reason why we must pass in the unrotated form
5581f0984d40SFabiano Rosas  * of the immediate.
5582f0984d40SFabiano Rosas  */
5583f0984d40SFabiano Rosas static bool op_s_rri_rot(DisasContext *s, arg_s_rri_rot *a,
5584f0984d40SFabiano Rosas                          void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32),
5585f0984d40SFabiano Rosas                          int logic_cc, StoreRegKind kind)
5586f0984d40SFabiano Rosas {
5587f0984d40SFabiano Rosas     TCGv_i32 tmp1;
5588f0984d40SFabiano Rosas     uint32_t imm;
5589f0984d40SFabiano Rosas 
5590f0984d40SFabiano Rosas     imm = ror32(a->imm, a->rot);
5591f0984d40SFabiano Rosas     if (logic_cc && a->rot) {
5592f0984d40SFabiano Rosas         tcg_gen_movi_i32(cpu_CF, imm >> 31);
5593f0984d40SFabiano Rosas     }
5594f0984d40SFabiano Rosas     tmp1 = load_reg(s, a->rn);
5595f0984d40SFabiano Rosas 
5596f0984d40SFabiano Rosas     gen(tmp1, tmp1, tcg_constant_i32(imm));
5597f0984d40SFabiano Rosas 
5598f0984d40SFabiano Rosas     if (logic_cc) {
5599f0984d40SFabiano Rosas         gen_logic_CC(tmp1);
5600f0984d40SFabiano Rosas     }
5601f0984d40SFabiano Rosas     return store_reg_kind(s, a->rd, tmp1, kind);
5602f0984d40SFabiano Rosas }
5603f0984d40SFabiano Rosas 
5604f0984d40SFabiano Rosas static bool op_s_rxi_rot(DisasContext *s, arg_s_rri_rot *a,
5605f0984d40SFabiano Rosas                          void (*gen)(TCGv_i32, TCGv_i32),
5606f0984d40SFabiano Rosas                          int logic_cc, StoreRegKind kind)
5607f0984d40SFabiano Rosas {
5608f0984d40SFabiano Rosas     TCGv_i32 tmp;
5609f0984d40SFabiano Rosas     uint32_t imm;
5610f0984d40SFabiano Rosas 
5611f0984d40SFabiano Rosas     imm = ror32(a->imm, a->rot);
5612f0984d40SFabiano Rosas     if (logic_cc && a->rot) {
5613f0984d40SFabiano Rosas         tcg_gen_movi_i32(cpu_CF, imm >> 31);
5614f0984d40SFabiano Rosas     }
5615f0984d40SFabiano Rosas 
5616f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
5617f0984d40SFabiano Rosas     gen(tmp, tcg_constant_i32(imm));
5618f0984d40SFabiano Rosas 
5619f0984d40SFabiano Rosas     if (logic_cc) {
5620f0984d40SFabiano Rosas         gen_logic_CC(tmp);
5621f0984d40SFabiano Rosas     }
5622f0984d40SFabiano Rosas     return store_reg_kind(s, a->rd, tmp, kind);
5623f0984d40SFabiano Rosas }
5624f0984d40SFabiano Rosas 
5625f0984d40SFabiano Rosas #define DO_ANY3(NAME, OP, L, K)                                         \
5626f0984d40SFabiano Rosas     static bool trans_##NAME##_rrri(DisasContext *s, arg_s_rrr_shi *a)  \
5627f0984d40SFabiano Rosas     { StoreRegKind k = (K); return op_s_rrr_shi(s, a, OP, L, k); }      \
5628f0984d40SFabiano Rosas     static bool trans_##NAME##_rrrr(DisasContext *s, arg_s_rrr_shr *a)  \
5629f0984d40SFabiano Rosas     { StoreRegKind k = (K); return op_s_rrr_shr(s, a, OP, L, k); }      \
5630f0984d40SFabiano Rosas     static bool trans_##NAME##_rri(DisasContext *s, arg_s_rri_rot *a)   \
5631f0984d40SFabiano Rosas     { StoreRegKind k = (K); return op_s_rri_rot(s, a, OP, L, k); }
5632f0984d40SFabiano Rosas 
5633f0984d40SFabiano Rosas #define DO_ANY2(NAME, OP, L, K)                                         \
5634f0984d40SFabiano Rosas     static bool trans_##NAME##_rxri(DisasContext *s, arg_s_rrr_shi *a)  \
5635f0984d40SFabiano Rosas     { StoreRegKind k = (K); return op_s_rxr_shi(s, a, OP, L, k); }      \
5636f0984d40SFabiano Rosas     static bool trans_##NAME##_rxrr(DisasContext *s, arg_s_rrr_shr *a)  \
5637f0984d40SFabiano Rosas     { StoreRegKind k = (K); return op_s_rxr_shr(s, a, OP, L, k); }      \
5638f0984d40SFabiano Rosas     static bool trans_##NAME##_rxi(DisasContext *s, arg_s_rri_rot *a)   \
5639f0984d40SFabiano Rosas     { StoreRegKind k = (K); return op_s_rxi_rot(s, a, OP, L, k); }
5640f0984d40SFabiano Rosas 
5641f0984d40SFabiano Rosas #define DO_CMP2(NAME, OP, L)                                            \
5642f0984d40SFabiano Rosas     static bool trans_##NAME##_xrri(DisasContext *s, arg_s_rrr_shi *a)  \
5643f0984d40SFabiano Rosas     { return op_s_rrr_shi(s, a, OP, L, STREG_NONE); }                   \
5644f0984d40SFabiano Rosas     static bool trans_##NAME##_xrrr(DisasContext *s, arg_s_rrr_shr *a)  \
5645f0984d40SFabiano Rosas     { return op_s_rrr_shr(s, a, OP, L, STREG_NONE); }                   \
5646f0984d40SFabiano Rosas     static bool trans_##NAME##_xri(DisasContext *s, arg_s_rri_rot *a)   \
5647f0984d40SFabiano Rosas     { return op_s_rri_rot(s, a, OP, L, STREG_NONE); }
5648f0984d40SFabiano Rosas 
5649f0984d40SFabiano Rosas DO_ANY3(AND, tcg_gen_and_i32, a->s, STREG_NORMAL)
5650f0984d40SFabiano Rosas DO_ANY3(EOR, tcg_gen_xor_i32, a->s, STREG_NORMAL)
5651f0984d40SFabiano Rosas DO_ANY3(ORR, tcg_gen_or_i32, a->s, STREG_NORMAL)
5652f0984d40SFabiano Rosas DO_ANY3(BIC, tcg_gen_andc_i32, a->s, STREG_NORMAL)
5653f0984d40SFabiano Rosas 
5654f0984d40SFabiano Rosas DO_ANY3(RSB, a->s ? gen_rsb_CC : gen_rsb, false, STREG_NORMAL)
5655f0984d40SFabiano Rosas DO_ANY3(ADC, a->s ? gen_adc_CC : gen_add_carry, false, STREG_NORMAL)
5656f0984d40SFabiano Rosas DO_ANY3(SBC, a->s ? gen_sbc_CC : gen_sub_carry, false, STREG_NORMAL)
5657f0984d40SFabiano Rosas DO_ANY3(RSC, a->s ? gen_rsc_CC : gen_rsc, false, STREG_NORMAL)
5658f0984d40SFabiano Rosas 
5659f0984d40SFabiano Rosas DO_CMP2(TST, tcg_gen_and_i32, true)
5660f0984d40SFabiano Rosas DO_CMP2(TEQ, tcg_gen_xor_i32, true)
5661f0984d40SFabiano Rosas DO_CMP2(CMN, gen_add_CC, false)
5662f0984d40SFabiano Rosas DO_CMP2(CMP, gen_sub_CC, false)
5663f0984d40SFabiano Rosas 
5664f0984d40SFabiano Rosas DO_ANY3(ADD, a->s ? gen_add_CC : tcg_gen_add_i32, false,
5665f0984d40SFabiano Rosas         a->rd == 13 && a->rn == 13 ? STREG_SP_CHECK : STREG_NORMAL)
5666f0984d40SFabiano Rosas 
5667f0984d40SFabiano Rosas /*
5668f0984d40SFabiano Rosas  * Note for the computation of StoreRegKind we return out of the
5669f0984d40SFabiano Rosas  * middle of the functions that are expanded by DO_ANY3, and that
5670f0984d40SFabiano Rosas  * we modify a->s via that parameter before it is used by OP.
5671f0984d40SFabiano Rosas  */
5672f0984d40SFabiano Rosas DO_ANY3(SUB, a->s ? gen_sub_CC : tcg_gen_sub_i32, false,
5673f0984d40SFabiano Rosas         ({
5674f0984d40SFabiano Rosas             StoreRegKind ret = STREG_NORMAL;
5675f0984d40SFabiano Rosas             if (a->rd == 15 && a->s) {
5676f0984d40SFabiano Rosas                 /*
5677f0984d40SFabiano Rosas                  * See ALUExceptionReturn:
5678f0984d40SFabiano Rosas                  * In User mode, UNPREDICTABLE; we choose UNDEF.
5679f0984d40SFabiano Rosas                  * In Hyp mode, UNDEFINED.
5680f0984d40SFabiano Rosas                  */
5681f0984d40SFabiano Rosas                 if (IS_USER(s) || s->current_el == 2) {
5682f0984d40SFabiano Rosas                     unallocated_encoding(s);
5683f0984d40SFabiano Rosas                     return true;
5684f0984d40SFabiano Rosas                 }
5685f0984d40SFabiano Rosas                 /* There is no writeback of nzcv to PSTATE.  */
5686f0984d40SFabiano Rosas                 a->s = 0;
5687f0984d40SFabiano Rosas                 ret = STREG_EXC_RET;
5688f0984d40SFabiano Rosas             } else if (a->rd == 13 && a->rn == 13) {
5689f0984d40SFabiano Rosas                 ret = STREG_SP_CHECK;
5690f0984d40SFabiano Rosas             }
5691f0984d40SFabiano Rosas             ret;
5692f0984d40SFabiano Rosas         }))
5693f0984d40SFabiano Rosas 
5694f0984d40SFabiano Rosas DO_ANY2(MOV, tcg_gen_mov_i32, a->s,
5695f0984d40SFabiano Rosas         ({
5696f0984d40SFabiano Rosas             StoreRegKind ret = STREG_NORMAL;
5697f0984d40SFabiano Rosas             if (a->rd == 15 && a->s) {
5698f0984d40SFabiano Rosas                 /*
5699f0984d40SFabiano Rosas                  * See ALUExceptionReturn:
5700f0984d40SFabiano Rosas                  * In User mode, UNPREDICTABLE; we choose UNDEF.
5701f0984d40SFabiano Rosas                  * In Hyp mode, UNDEFINED.
5702f0984d40SFabiano Rosas                  */
5703f0984d40SFabiano Rosas                 if (IS_USER(s) || s->current_el == 2) {
5704f0984d40SFabiano Rosas                     unallocated_encoding(s);
5705f0984d40SFabiano Rosas                     return true;
5706f0984d40SFabiano Rosas                 }
5707f0984d40SFabiano Rosas                 /* There is no writeback of nzcv to PSTATE.  */
5708f0984d40SFabiano Rosas                 a->s = 0;
5709f0984d40SFabiano Rosas                 ret = STREG_EXC_RET;
5710f0984d40SFabiano Rosas             } else if (a->rd == 13) {
5711f0984d40SFabiano Rosas                 ret = STREG_SP_CHECK;
5712f0984d40SFabiano Rosas             }
5713f0984d40SFabiano Rosas             ret;
5714f0984d40SFabiano Rosas         }))
5715f0984d40SFabiano Rosas 
5716f0984d40SFabiano Rosas DO_ANY2(MVN, tcg_gen_not_i32, a->s, STREG_NORMAL)
5717f0984d40SFabiano Rosas 
5718f0984d40SFabiano Rosas /*
5719f0984d40SFabiano Rosas  * ORN is only available with T32, so there is no register-shifted-register
5720f0984d40SFabiano Rosas  * form of the insn.  Using the DO_ANY3 macro would create an unused function.
5721f0984d40SFabiano Rosas  */
5722f0984d40SFabiano Rosas static bool trans_ORN_rrri(DisasContext *s, arg_s_rrr_shi *a)
5723f0984d40SFabiano Rosas {
5724f0984d40SFabiano Rosas     return op_s_rrr_shi(s, a, tcg_gen_orc_i32, a->s, STREG_NORMAL);
5725f0984d40SFabiano Rosas }
5726f0984d40SFabiano Rosas 
5727f0984d40SFabiano Rosas static bool trans_ORN_rri(DisasContext *s, arg_s_rri_rot *a)
5728f0984d40SFabiano Rosas {
5729f0984d40SFabiano Rosas     return op_s_rri_rot(s, a, tcg_gen_orc_i32, a->s, STREG_NORMAL);
5730f0984d40SFabiano Rosas }
5731f0984d40SFabiano Rosas 
5732f0984d40SFabiano Rosas #undef DO_ANY3
5733f0984d40SFabiano Rosas #undef DO_ANY2
5734f0984d40SFabiano Rosas #undef DO_CMP2
5735f0984d40SFabiano Rosas 
5736f0984d40SFabiano Rosas static bool trans_ADR(DisasContext *s, arg_ri *a)
5737f0984d40SFabiano Rosas {
5738f0984d40SFabiano Rosas     store_reg_bx(s, a->rd, add_reg_for_lit(s, 15, a->imm));
5739f0984d40SFabiano Rosas     return true;
5740f0984d40SFabiano Rosas }
5741f0984d40SFabiano Rosas 
5742f0984d40SFabiano Rosas static bool trans_MOVW(DisasContext *s, arg_MOVW *a)
5743f0984d40SFabiano Rosas {
5744f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6T2) {
5745f0984d40SFabiano Rosas         return false;
5746f0984d40SFabiano Rosas     }
5747f0984d40SFabiano Rosas 
5748f0984d40SFabiano Rosas     store_reg(s, a->rd, tcg_constant_i32(a->imm));
5749f0984d40SFabiano Rosas     return true;
5750f0984d40SFabiano Rosas }
5751f0984d40SFabiano Rosas 
5752f0984d40SFabiano Rosas static bool trans_MOVT(DisasContext *s, arg_MOVW *a)
5753f0984d40SFabiano Rosas {
5754f0984d40SFabiano Rosas     TCGv_i32 tmp;
5755f0984d40SFabiano Rosas 
5756f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6T2) {
5757f0984d40SFabiano Rosas         return false;
5758f0984d40SFabiano Rosas     }
5759f0984d40SFabiano Rosas 
5760f0984d40SFabiano Rosas     tmp = load_reg(s, a->rd);
5761f0984d40SFabiano Rosas     tcg_gen_ext16u_i32(tmp, tmp);
5762f0984d40SFabiano Rosas     tcg_gen_ori_i32(tmp, tmp, a->imm << 16);
5763f0984d40SFabiano Rosas     store_reg(s, a->rd, tmp);
5764f0984d40SFabiano Rosas     return true;
5765f0984d40SFabiano Rosas }
5766f0984d40SFabiano Rosas 
5767f0984d40SFabiano Rosas /*
5768f0984d40SFabiano Rosas  * v8.1M MVE wide-shifts
5769f0984d40SFabiano Rosas  */
5770f0984d40SFabiano Rosas static bool do_mve_shl_ri(DisasContext *s, arg_mve_shl_ri *a,
5771f0984d40SFabiano Rosas                           WideShiftImmFn *fn)
5772f0984d40SFabiano Rosas {
5773f0984d40SFabiano Rosas     TCGv_i64 rda;
5774f0984d40SFabiano Rosas     TCGv_i32 rdalo, rdahi;
5775f0984d40SFabiano Rosas 
5776f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
5777f0984d40SFabiano Rosas         /* Decode falls through to ORR/MOV UNPREDICTABLE handling */
5778f0984d40SFabiano Rosas         return false;
5779f0984d40SFabiano Rosas     }
5780f0984d40SFabiano Rosas     if (a->rdahi == 15) {
5781f0984d40SFabiano Rosas         /* These are a different encoding (SQSHL/SRSHR/UQSHL/URSHR) */
5782f0984d40SFabiano Rosas         return false;
5783f0984d40SFabiano Rosas     }
5784f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_mve, s) ||
5785f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_M_MAIN) ||
5786f0984d40SFabiano Rosas         a->rdahi == 13) {
5787f0984d40SFabiano Rosas         /* RdaHi == 13 is UNPREDICTABLE; we choose to UNDEF */
5788f0984d40SFabiano Rosas         unallocated_encoding(s);
5789f0984d40SFabiano Rosas         return true;
5790f0984d40SFabiano Rosas     }
5791f0984d40SFabiano Rosas 
5792f0984d40SFabiano Rosas     if (a->shim == 0) {
5793f0984d40SFabiano Rosas         a->shim = 32;
5794f0984d40SFabiano Rosas     }
5795f0984d40SFabiano Rosas 
5796f0984d40SFabiano Rosas     rda = tcg_temp_new_i64();
5797f0984d40SFabiano Rosas     rdalo = load_reg(s, a->rdalo);
5798f0984d40SFabiano Rosas     rdahi = load_reg(s, a->rdahi);
5799f0984d40SFabiano Rosas     tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
5800f0984d40SFabiano Rosas 
5801f0984d40SFabiano Rosas     fn(rda, rda, a->shim);
5802f0984d40SFabiano Rosas 
5803f0984d40SFabiano Rosas     tcg_gen_extrl_i64_i32(rdalo, rda);
5804f0984d40SFabiano Rosas     tcg_gen_extrh_i64_i32(rdahi, rda);
5805f0984d40SFabiano Rosas     store_reg(s, a->rdalo, rdalo);
5806f0984d40SFabiano Rosas     store_reg(s, a->rdahi, rdahi);
5807f0984d40SFabiano Rosas     tcg_temp_free_i64(rda);
5808f0984d40SFabiano Rosas 
5809f0984d40SFabiano Rosas     return true;
5810f0984d40SFabiano Rosas }
5811f0984d40SFabiano Rosas 
5812f0984d40SFabiano Rosas static bool trans_ASRL_ri(DisasContext *s, arg_mve_shl_ri *a)
5813f0984d40SFabiano Rosas {
5814f0984d40SFabiano Rosas     return do_mve_shl_ri(s, a, tcg_gen_sari_i64);
5815f0984d40SFabiano Rosas }
5816f0984d40SFabiano Rosas 
5817f0984d40SFabiano Rosas static bool trans_LSLL_ri(DisasContext *s, arg_mve_shl_ri *a)
5818f0984d40SFabiano Rosas {
5819f0984d40SFabiano Rosas     return do_mve_shl_ri(s, a, tcg_gen_shli_i64);
5820f0984d40SFabiano Rosas }
5821f0984d40SFabiano Rosas 
5822f0984d40SFabiano Rosas static bool trans_LSRL_ri(DisasContext *s, arg_mve_shl_ri *a)
5823f0984d40SFabiano Rosas {
5824f0984d40SFabiano Rosas     return do_mve_shl_ri(s, a, tcg_gen_shri_i64);
5825f0984d40SFabiano Rosas }
5826f0984d40SFabiano Rosas 
5827f0984d40SFabiano Rosas static void gen_mve_sqshll(TCGv_i64 r, TCGv_i64 n, int64_t shift)
5828f0984d40SFabiano Rosas {
5829f0984d40SFabiano Rosas     gen_helper_mve_sqshll(r, cpu_env, n, tcg_constant_i32(shift));
5830f0984d40SFabiano Rosas }
5831f0984d40SFabiano Rosas 
5832f0984d40SFabiano Rosas static bool trans_SQSHLL_ri(DisasContext *s, arg_mve_shl_ri *a)
5833f0984d40SFabiano Rosas {
5834f0984d40SFabiano Rosas     return do_mve_shl_ri(s, a, gen_mve_sqshll);
5835f0984d40SFabiano Rosas }
5836f0984d40SFabiano Rosas 
5837f0984d40SFabiano Rosas static void gen_mve_uqshll(TCGv_i64 r, TCGv_i64 n, int64_t shift)
5838f0984d40SFabiano Rosas {
5839f0984d40SFabiano Rosas     gen_helper_mve_uqshll(r, cpu_env, n, tcg_constant_i32(shift));
5840f0984d40SFabiano Rosas }
5841f0984d40SFabiano Rosas 
5842f0984d40SFabiano Rosas static bool trans_UQSHLL_ri(DisasContext *s, arg_mve_shl_ri *a)
5843f0984d40SFabiano Rosas {
5844f0984d40SFabiano Rosas     return do_mve_shl_ri(s, a, gen_mve_uqshll);
5845f0984d40SFabiano Rosas }
5846f0984d40SFabiano Rosas 
5847f0984d40SFabiano Rosas static bool trans_SRSHRL_ri(DisasContext *s, arg_mve_shl_ri *a)
5848f0984d40SFabiano Rosas {
5849f0984d40SFabiano Rosas     return do_mve_shl_ri(s, a, gen_srshr64_i64);
5850f0984d40SFabiano Rosas }
5851f0984d40SFabiano Rosas 
5852f0984d40SFabiano Rosas static bool trans_URSHRL_ri(DisasContext *s, arg_mve_shl_ri *a)
5853f0984d40SFabiano Rosas {
5854f0984d40SFabiano Rosas     return do_mve_shl_ri(s, a, gen_urshr64_i64);
5855f0984d40SFabiano Rosas }
5856f0984d40SFabiano Rosas 
5857f0984d40SFabiano Rosas static bool do_mve_shl_rr(DisasContext *s, arg_mve_shl_rr *a, WideShiftFn *fn)
5858f0984d40SFabiano Rosas {
5859f0984d40SFabiano Rosas     TCGv_i64 rda;
5860f0984d40SFabiano Rosas     TCGv_i32 rdalo, rdahi;
5861f0984d40SFabiano Rosas 
5862f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
5863f0984d40SFabiano Rosas         /* Decode falls through to ORR/MOV UNPREDICTABLE handling */
5864f0984d40SFabiano Rosas         return false;
5865f0984d40SFabiano Rosas     }
5866f0984d40SFabiano Rosas     if (a->rdahi == 15) {
5867f0984d40SFabiano Rosas         /* These are a different encoding (SQSHL/SRSHR/UQSHL/URSHR) */
5868f0984d40SFabiano Rosas         return false;
5869f0984d40SFabiano Rosas     }
5870f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_mve, s) ||
5871f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_M_MAIN) ||
5872f0984d40SFabiano Rosas         a->rdahi == 13 || a->rm == 13 || a->rm == 15 ||
5873f0984d40SFabiano Rosas         a->rm == a->rdahi || a->rm == a->rdalo) {
5874f0984d40SFabiano Rosas         /* These rdahi/rdalo/rm cases are UNPREDICTABLE; we choose to UNDEF */
5875f0984d40SFabiano Rosas         unallocated_encoding(s);
5876f0984d40SFabiano Rosas         return true;
5877f0984d40SFabiano Rosas     }
5878f0984d40SFabiano Rosas 
5879f0984d40SFabiano Rosas     rda = tcg_temp_new_i64();
5880f0984d40SFabiano Rosas     rdalo = load_reg(s, a->rdalo);
5881f0984d40SFabiano Rosas     rdahi = load_reg(s, a->rdahi);
5882f0984d40SFabiano Rosas     tcg_gen_concat_i32_i64(rda, rdalo, rdahi);
5883f0984d40SFabiano Rosas 
5884f0984d40SFabiano Rosas     /* The helper takes care of the sign-extension of the low 8 bits of Rm */
5885f0984d40SFabiano Rosas     fn(rda, cpu_env, rda, cpu_R[a->rm]);
5886f0984d40SFabiano Rosas 
5887f0984d40SFabiano Rosas     tcg_gen_extrl_i64_i32(rdalo, rda);
5888f0984d40SFabiano Rosas     tcg_gen_extrh_i64_i32(rdahi, rda);
5889f0984d40SFabiano Rosas     store_reg(s, a->rdalo, rdalo);
5890f0984d40SFabiano Rosas     store_reg(s, a->rdahi, rdahi);
5891f0984d40SFabiano Rosas     tcg_temp_free_i64(rda);
5892f0984d40SFabiano Rosas 
5893f0984d40SFabiano Rosas     return true;
5894f0984d40SFabiano Rosas }
5895f0984d40SFabiano Rosas 
5896f0984d40SFabiano Rosas static bool trans_LSLL_rr(DisasContext *s, arg_mve_shl_rr *a)
5897f0984d40SFabiano Rosas {
5898f0984d40SFabiano Rosas     return do_mve_shl_rr(s, a, gen_helper_mve_ushll);
5899f0984d40SFabiano Rosas }
5900f0984d40SFabiano Rosas 
5901f0984d40SFabiano Rosas static bool trans_ASRL_rr(DisasContext *s, arg_mve_shl_rr *a)
5902f0984d40SFabiano Rosas {
5903f0984d40SFabiano Rosas     return do_mve_shl_rr(s, a, gen_helper_mve_sshrl);
5904f0984d40SFabiano Rosas }
5905f0984d40SFabiano Rosas 
5906f0984d40SFabiano Rosas static bool trans_UQRSHLL64_rr(DisasContext *s, arg_mve_shl_rr *a)
5907f0984d40SFabiano Rosas {
5908f0984d40SFabiano Rosas     return do_mve_shl_rr(s, a, gen_helper_mve_uqrshll);
5909f0984d40SFabiano Rosas }
5910f0984d40SFabiano Rosas 
5911f0984d40SFabiano Rosas static bool trans_SQRSHRL64_rr(DisasContext *s, arg_mve_shl_rr *a)
5912f0984d40SFabiano Rosas {
5913f0984d40SFabiano Rosas     return do_mve_shl_rr(s, a, gen_helper_mve_sqrshrl);
5914f0984d40SFabiano Rosas }
5915f0984d40SFabiano Rosas 
5916f0984d40SFabiano Rosas static bool trans_UQRSHLL48_rr(DisasContext *s, arg_mve_shl_rr *a)
5917f0984d40SFabiano Rosas {
5918f0984d40SFabiano Rosas     return do_mve_shl_rr(s, a, gen_helper_mve_uqrshll48);
5919f0984d40SFabiano Rosas }
5920f0984d40SFabiano Rosas 
5921f0984d40SFabiano Rosas static bool trans_SQRSHRL48_rr(DisasContext *s, arg_mve_shl_rr *a)
5922f0984d40SFabiano Rosas {
5923f0984d40SFabiano Rosas     return do_mve_shl_rr(s, a, gen_helper_mve_sqrshrl48);
5924f0984d40SFabiano Rosas }
5925f0984d40SFabiano Rosas 
5926f0984d40SFabiano Rosas static bool do_mve_sh_ri(DisasContext *s, arg_mve_sh_ri *a, ShiftImmFn *fn)
5927f0984d40SFabiano Rosas {
5928f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
5929f0984d40SFabiano Rosas         /* Decode falls through to ORR/MOV UNPREDICTABLE handling */
5930f0984d40SFabiano Rosas         return false;
5931f0984d40SFabiano Rosas     }
5932f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_mve, s) ||
5933f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_M_MAIN) ||
5934f0984d40SFabiano Rosas         a->rda == 13 || a->rda == 15) {
5935f0984d40SFabiano Rosas         /* These rda cases are UNPREDICTABLE; we choose to UNDEF */
5936f0984d40SFabiano Rosas         unallocated_encoding(s);
5937f0984d40SFabiano Rosas         return true;
5938f0984d40SFabiano Rosas     }
5939f0984d40SFabiano Rosas 
5940f0984d40SFabiano Rosas     if (a->shim == 0) {
5941f0984d40SFabiano Rosas         a->shim = 32;
5942f0984d40SFabiano Rosas     }
5943f0984d40SFabiano Rosas     fn(cpu_R[a->rda], cpu_R[a->rda], a->shim);
5944f0984d40SFabiano Rosas 
5945f0984d40SFabiano Rosas     return true;
5946f0984d40SFabiano Rosas }
5947f0984d40SFabiano Rosas 
5948f0984d40SFabiano Rosas static bool trans_URSHR_ri(DisasContext *s, arg_mve_sh_ri *a)
5949f0984d40SFabiano Rosas {
5950f0984d40SFabiano Rosas     return do_mve_sh_ri(s, a, gen_urshr32_i32);
5951f0984d40SFabiano Rosas }
5952f0984d40SFabiano Rosas 
5953f0984d40SFabiano Rosas static bool trans_SRSHR_ri(DisasContext *s, arg_mve_sh_ri *a)
5954f0984d40SFabiano Rosas {
5955f0984d40SFabiano Rosas     return do_mve_sh_ri(s, a, gen_srshr32_i32);
5956f0984d40SFabiano Rosas }
5957f0984d40SFabiano Rosas 
5958f0984d40SFabiano Rosas static void gen_mve_sqshl(TCGv_i32 r, TCGv_i32 n, int32_t shift)
5959f0984d40SFabiano Rosas {
5960f0984d40SFabiano Rosas     gen_helper_mve_sqshl(r, cpu_env, n, tcg_constant_i32(shift));
5961f0984d40SFabiano Rosas }
5962f0984d40SFabiano Rosas 
5963f0984d40SFabiano Rosas static bool trans_SQSHL_ri(DisasContext *s, arg_mve_sh_ri *a)
5964f0984d40SFabiano Rosas {
5965f0984d40SFabiano Rosas     return do_mve_sh_ri(s, a, gen_mve_sqshl);
5966f0984d40SFabiano Rosas }
5967f0984d40SFabiano Rosas 
5968f0984d40SFabiano Rosas static void gen_mve_uqshl(TCGv_i32 r, TCGv_i32 n, int32_t shift)
5969f0984d40SFabiano Rosas {
5970f0984d40SFabiano Rosas     gen_helper_mve_uqshl(r, cpu_env, n, tcg_constant_i32(shift));
5971f0984d40SFabiano Rosas }
5972f0984d40SFabiano Rosas 
5973f0984d40SFabiano Rosas static bool trans_UQSHL_ri(DisasContext *s, arg_mve_sh_ri *a)
5974f0984d40SFabiano Rosas {
5975f0984d40SFabiano Rosas     return do_mve_sh_ri(s, a, gen_mve_uqshl);
5976f0984d40SFabiano Rosas }
5977f0984d40SFabiano Rosas 
5978f0984d40SFabiano Rosas static bool do_mve_sh_rr(DisasContext *s, arg_mve_sh_rr *a, ShiftFn *fn)
5979f0984d40SFabiano Rosas {
5980f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
5981f0984d40SFabiano Rosas         /* Decode falls through to ORR/MOV UNPREDICTABLE handling */
5982f0984d40SFabiano Rosas         return false;
5983f0984d40SFabiano Rosas     }
5984f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_mve, s) ||
5985f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_M_MAIN) ||
5986f0984d40SFabiano Rosas         a->rda == 13 || a->rda == 15 || a->rm == 13 || a->rm == 15 ||
5987f0984d40SFabiano Rosas         a->rm == a->rda) {
5988f0984d40SFabiano Rosas         /* These rda/rm cases are UNPREDICTABLE; we choose to UNDEF */
5989f0984d40SFabiano Rosas         unallocated_encoding(s);
5990f0984d40SFabiano Rosas         return true;
5991f0984d40SFabiano Rosas     }
5992f0984d40SFabiano Rosas 
5993f0984d40SFabiano Rosas     /* The helper takes care of the sign-extension of the low 8 bits of Rm */
5994f0984d40SFabiano Rosas     fn(cpu_R[a->rda], cpu_env, cpu_R[a->rda], cpu_R[a->rm]);
5995f0984d40SFabiano Rosas     return true;
5996f0984d40SFabiano Rosas }
5997f0984d40SFabiano Rosas 
5998f0984d40SFabiano Rosas static bool trans_SQRSHR_rr(DisasContext *s, arg_mve_sh_rr *a)
5999f0984d40SFabiano Rosas {
6000f0984d40SFabiano Rosas     return do_mve_sh_rr(s, a, gen_helper_mve_sqrshr);
6001f0984d40SFabiano Rosas }
6002f0984d40SFabiano Rosas 
6003f0984d40SFabiano Rosas static bool trans_UQRSHL_rr(DisasContext *s, arg_mve_sh_rr *a)
6004f0984d40SFabiano Rosas {
6005f0984d40SFabiano Rosas     return do_mve_sh_rr(s, a, gen_helper_mve_uqrshl);
6006f0984d40SFabiano Rosas }
6007f0984d40SFabiano Rosas 
6008f0984d40SFabiano Rosas /*
6009f0984d40SFabiano Rosas  * Multiply and multiply accumulate
6010f0984d40SFabiano Rosas  */
6011f0984d40SFabiano Rosas 
6012f0984d40SFabiano Rosas static bool op_mla(DisasContext *s, arg_s_rrrr *a, bool add)
6013f0984d40SFabiano Rosas {
6014f0984d40SFabiano Rosas     TCGv_i32 t1, t2;
6015f0984d40SFabiano Rosas 
6016f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
6017f0984d40SFabiano Rosas     t2 = load_reg(s, a->rm);
6018f0984d40SFabiano Rosas     tcg_gen_mul_i32(t1, t1, t2);
6019f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
6020f0984d40SFabiano Rosas     if (add) {
6021f0984d40SFabiano Rosas         t2 = load_reg(s, a->ra);
6022f0984d40SFabiano Rosas         tcg_gen_add_i32(t1, t1, t2);
6023f0984d40SFabiano Rosas         tcg_temp_free_i32(t2);
6024f0984d40SFabiano Rosas     }
6025f0984d40SFabiano Rosas     if (a->s) {
6026f0984d40SFabiano Rosas         gen_logic_CC(t1);
6027f0984d40SFabiano Rosas     }
6028f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
6029f0984d40SFabiano Rosas     return true;
6030f0984d40SFabiano Rosas }
6031f0984d40SFabiano Rosas 
6032f0984d40SFabiano Rosas static bool trans_MUL(DisasContext *s, arg_MUL *a)
6033f0984d40SFabiano Rosas {
6034f0984d40SFabiano Rosas     return op_mla(s, a, false);
6035f0984d40SFabiano Rosas }
6036f0984d40SFabiano Rosas 
6037f0984d40SFabiano Rosas static bool trans_MLA(DisasContext *s, arg_MLA *a)
6038f0984d40SFabiano Rosas {
6039f0984d40SFabiano Rosas     return op_mla(s, a, true);
6040f0984d40SFabiano Rosas }
6041f0984d40SFabiano Rosas 
6042f0984d40SFabiano Rosas static bool trans_MLS(DisasContext *s, arg_MLS *a)
6043f0984d40SFabiano Rosas {
6044f0984d40SFabiano Rosas     TCGv_i32 t1, t2;
6045f0984d40SFabiano Rosas 
6046f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6T2) {
6047f0984d40SFabiano Rosas         return false;
6048f0984d40SFabiano Rosas     }
6049f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
6050f0984d40SFabiano Rosas     t2 = load_reg(s, a->rm);
6051f0984d40SFabiano Rosas     tcg_gen_mul_i32(t1, t1, t2);
6052f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
6053f0984d40SFabiano Rosas     t2 = load_reg(s, a->ra);
6054f0984d40SFabiano Rosas     tcg_gen_sub_i32(t1, t2, t1);
6055f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
6056f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
6057f0984d40SFabiano Rosas     return true;
6058f0984d40SFabiano Rosas }
6059f0984d40SFabiano Rosas 
6060f0984d40SFabiano Rosas static bool op_mlal(DisasContext *s, arg_s_rrrr *a, bool uns, bool add)
6061f0984d40SFabiano Rosas {
6062f0984d40SFabiano Rosas     TCGv_i32 t0, t1, t2, t3;
6063f0984d40SFabiano Rosas 
6064f0984d40SFabiano Rosas     t0 = load_reg(s, a->rm);
6065f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
6066f0984d40SFabiano Rosas     if (uns) {
6067f0984d40SFabiano Rosas         tcg_gen_mulu2_i32(t0, t1, t0, t1);
6068f0984d40SFabiano Rosas     } else {
6069f0984d40SFabiano Rosas         tcg_gen_muls2_i32(t0, t1, t0, t1);
6070f0984d40SFabiano Rosas     }
6071f0984d40SFabiano Rosas     if (add) {
6072f0984d40SFabiano Rosas         t2 = load_reg(s, a->ra);
6073f0984d40SFabiano Rosas         t3 = load_reg(s, a->rd);
6074f0984d40SFabiano Rosas         tcg_gen_add2_i32(t0, t1, t0, t1, t2, t3);
6075f0984d40SFabiano Rosas         tcg_temp_free_i32(t2);
6076f0984d40SFabiano Rosas         tcg_temp_free_i32(t3);
6077f0984d40SFabiano Rosas     }
6078f0984d40SFabiano Rosas     if (a->s) {
6079f0984d40SFabiano Rosas         gen_logicq_cc(t0, t1);
6080f0984d40SFabiano Rosas     }
6081f0984d40SFabiano Rosas     store_reg(s, a->ra, t0);
6082f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
6083f0984d40SFabiano Rosas     return true;
6084f0984d40SFabiano Rosas }
6085f0984d40SFabiano Rosas 
6086f0984d40SFabiano Rosas static bool trans_UMULL(DisasContext *s, arg_UMULL *a)
6087f0984d40SFabiano Rosas {
6088f0984d40SFabiano Rosas     return op_mlal(s, a, true, false);
6089f0984d40SFabiano Rosas }
6090f0984d40SFabiano Rosas 
6091f0984d40SFabiano Rosas static bool trans_SMULL(DisasContext *s, arg_SMULL *a)
6092f0984d40SFabiano Rosas {
6093f0984d40SFabiano Rosas     return op_mlal(s, a, false, false);
6094f0984d40SFabiano Rosas }
6095f0984d40SFabiano Rosas 
6096f0984d40SFabiano Rosas static bool trans_UMLAL(DisasContext *s, arg_UMLAL *a)
6097f0984d40SFabiano Rosas {
6098f0984d40SFabiano Rosas     return op_mlal(s, a, true, true);
6099f0984d40SFabiano Rosas }
6100f0984d40SFabiano Rosas 
6101f0984d40SFabiano Rosas static bool trans_SMLAL(DisasContext *s, arg_SMLAL *a)
6102f0984d40SFabiano Rosas {
6103f0984d40SFabiano Rosas     return op_mlal(s, a, false, true);
6104f0984d40SFabiano Rosas }
6105f0984d40SFabiano Rosas 
6106f0984d40SFabiano Rosas static bool trans_UMAAL(DisasContext *s, arg_UMAAL *a)
6107f0984d40SFabiano Rosas {
6108f0984d40SFabiano Rosas     TCGv_i32 t0, t1, t2, zero;
6109f0984d40SFabiano Rosas 
6110f0984d40SFabiano Rosas     if (s->thumb
6111f0984d40SFabiano Rosas         ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
6112f0984d40SFabiano Rosas         : !ENABLE_ARCH_6) {
6113f0984d40SFabiano Rosas         return false;
6114f0984d40SFabiano Rosas     }
6115f0984d40SFabiano Rosas 
6116f0984d40SFabiano Rosas     t0 = load_reg(s, a->rm);
6117f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
6118f0984d40SFabiano Rosas     tcg_gen_mulu2_i32(t0, t1, t0, t1);
6119f0984d40SFabiano Rosas     zero = tcg_constant_i32(0);
6120f0984d40SFabiano Rosas     t2 = load_reg(s, a->ra);
6121f0984d40SFabiano Rosas     tcg_gen_add2_i32(t0, t1, t0, t1, t2, zero);
6122f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
6123f0984d40SFabiano Rosas     t2 = load_reg(s, a->rd);
6124f0984d40SFabiano Rosas     tcg_gen_add2_i32(t0, t1, t0, t1, t2, zero);
6125f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
6126f0984d40SFabiano Rosas     store_reg(s, a->ra, t0);
6127f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
6128f0984d40SFabiano Rosas     return true;
6129f0984d40SFabiano Rosas }
6130f0984d40SFabiano Rosas 
6131f0984d40SFabiano Rosas /*
6132f0984d40SFabiano Rosas  * Saturating addition and subtraction
6133f0984d40SFabiano Rosas  */
6134f0984d40SFabiano Rosas 
6135f0984d40SFabiano Rosas static bool op_qaddsub(DisasContext *s, arg_rrr *a, bool add, bool doub)
6136f0984d40SFabiano Rosas {
6137f0984d40SFabiano Rosas     TCGv_i32 t0, t1;
6138f0984d40SFabiano Rosas 
6139f0984d40SFabiano Rosas     if (s->thumb
6140f0984d40SFabiano Rosas         ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
6141f0984d40SFabiano Rosas         : !ENABLE_ARCH_5TE) {
6142f0984d40SFabiano Rosas         return false;
6143f0984d40SFabiano Rosas     }
6144f0984d40SFabiano Rosas 
6145f0984d40SFabiano Rosas     t0 = load_reg(s, a->rm);
6146f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
6147f0984d40SFabiano Rosas     if (doub) {
6148f0984d40SFabiano Rosas         gen_helper_add_saturate(t1, cpu_env, t1, t1);
6149f0984d40SFabiano Rosas     }
6150f0984d40SFabiano Rosas     if (add) {
6151f0984d40SFabiano Rosas         gen_helper_add_saturate(t0, cpu_env, t0, t1);
6152f0984d40SFabiano Rosas     } else {
6153f0984d40SFabiano Rosas         gen_helper_sub_saturate(t0, cpu_env, t0, t1);
6154f0984d40SFabiano Rosas     }
6155f0984d40SFabiano Rosas     tcg_temp_free_i32(t1);
6156f0984d40SFabiano Rosas     store_reg(s, a->rd, t0);
6157f0984d40SFabiano Rosas     return true;
6158f0984d40SFabiano Rosas }
6159f0984d40SFabiano Rosas 
6160f0984d40SFabiano Rosas #define DO_QADDSUB(NAME, ADD, DOUB) \
6161f0984d40SFabiano Rosas static bool trans_##NAME(DisasContext *s, arg_rrr *a)    \
6162f0984d40SFabiano Rosas {                                                        \
6163f0984d40SFabiano Rosas     return op_qaddsub(s, a, ADD, DOUB);                  \
6164f0984d40SFabiano Rosas }
6165f0984d40SFabiano Rosas 
6166f0984d40SFabiano Rosas DO_QADDSUB(QADD, true, false)
6167f0984d40SFabiano Rosas DO_QADDSUB(QSUB, false, false)
6168f0984d40SFabiano Rosas DO_QADDSUB(QDADD, true, true)
6169f0984d40SFabiano Rosas DO_QADDSUB(QDSUB, false, true)
6170f0984d40SFabiano Rosas 
6171f0984d40SFabiano Rosas #undef DO_QADDSUB
6172f0984d40SFabiano Rosas 
6173f0984d40SFabiano Rosas /*
6174f0984d40SFabiano Rosas  * Halfword multiply and multiply accumulate
6175f0984d40SFabiano Rosas  */
6176f0984d40SFabiano Rosas 
6177f0984d40SFabiano Rosas static bool op_smlaxxx(DisasContext *s, arg_rrrr *a,
6178f0984d40SFabiano Rosas                        int add_long, bool nt, bool mt)
6179f0984d40SFabiano Rosas {
6180f0984d40SFabiano Rosas     TCGv_i32 t0, t1, tl, th;
6181f0984d40SFabiano Rosas 
6182f0984d40SFabiano Rosas     if (s->thumb
6183f0984d40SFabiano Rosas         ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
6184f0984d40SFabiano Rosas         : !ENABLE_ARCH_5TE) {
6185f0984d40SFabiano Rosas         return false;
6186f0984d40SFabiano Rosas     }
6187f0984d40SFabiano Rosas 
6188f0984d40SFabiano Rosas     t0 = load_reg(s, a->rn);
6189f0984d40SFabiano Rosas     t1 = load_reg(s, a->rm);
6190f0984d40SFabiano Rosas     gen_mulxy(t0, t1, nt, mt);
6191f0984d40SFabiano Rosas     tcg_temp_free_i32(t1);
6192f0984d40SFabiano Rosas 
6193f0984d40SFabiano Rosas     switch (add_long) {
6194f0984d40SFabiano Rosas     case 0:
6195f0984d40SFabiano Rosas         store_reg(s, a->rd, t0);
6196f0984d40SFabiano Rosas         break;
6197f0984d40SFabiano Rosas     case 1:
6198f0984d40SFabiano Rosas         t1 = load_reg(s, a->ra);
6199f0984d40SFabiano Rosas         gen_helper_add_setq(t0, cpu_env, t0, t1);
6200f0984d40SFabiano Rosas         tcg_temp_free_i32(t1);
6201f0984d40SFabiano Rosas         store_reg(s, a->rd, t0);
6202f0984d40SFabiano Rosas         break;
6203f0984d40SFabiano Rosas     case 2:
6204f0984d40SFabiano Rosas         tl = load_reg(s, a->ra);
6205f0984d40SFabiano Rosas         th = load_reg(s, a->rd);
6206f0984d40SFabiano Rosas         /* Sign-extend the 32-bit product to 64 bits.  */
6207f0984d40SFabiano Rosas         t1 = tcg_temp_new_i32();
6208f0984d40SFabiano Rosas         tcg_gen_sari_i32(t1, t0, 31);
6209f0984d40SFabiano Rosas         tcg_gen_add2_i32(tl, th, tl, th, t0, t1);
6210f0984d40SFabiano Rosas         tcg_temp_free_i32(t0);
6211f0984d40SFabiano Rosas         tcg_temp_free_i32(t1);
6212f0984d40SFabiano Rosas         store_reg(s, a->ra, tl);
6213f0984d40SFabiano Rosas         store_reg(s, a->rd, th);
6214f0984d40SFabiano Rosas         break;
6215f0984d40SFabiano Rosas     default:
6216f0984d40SFabiano Rosas         g_assert_not_reached();
6217f0984d40SFabiano Rosas     }
6218f0984d40SFabiano Rosas     return true;
6219f0984d40SFabiano Rosas }
6220f0984d40SFabiano Rosas 
6221f0984d40SFabiano Rosas #define DO_SMLAX(NAME, add, nt, mt) \
6222f0984d40SFabiano Rosas static bool trans_##NAME(DisasContext *s, arg_rrrr *a)     \
6223f0984d40SFabiano Rosas {                                                          \
6224f0984d40SFabiano Rosas     return op_smlaxxx(s, a, add, nt, mt);                  \
6225f0984d40SFabiano Rosas }
6226f0984d40SFabiano Rosas 
6227f0984d40SFabiano Rosas DO_SMLAX(SMULBB, 0, 0, 0)
6228f0984d40SFabiano Rosas DO_SMLAX(SMULBT, 0, 0, 1)
6229f0984d40SFabiano Rosas DO_SMLAX(SMULTB, 0, 1, 0)
6230f0984d40SFabiano Rosas DO_SMLAX(SMULTT, 0, 1, 1)
6231f0984d40SFabiano Rosas 
6232f0984d40SFabiano Rosas DO_SMLAX(SMLABB, 1, 0, 0)
6233f0984d40SFabiano Rosas DO_SMLAX(SMLABT, 1, 0, 1)
6234f0984d40SFabiano Rosas DO_SMLAX(SMLATB, 1, 1, 0)
6235f0984d40SFabiano Rosas DO_SMLAX(SMLATT, 1, 1, 1)
6236f0984d40SFabiano Rosas 
6237f0984d40SFabiano Rosas DO_SMLAX(SMLALBB, 2, 0, 0)
6238f0984d40SFabiano Rosas DO_SMLAX(SMLALBT, 2, 0, 1)
6239f0984d40SFabiano Rosas DO_SMLAX(SMLALTB, 2, 1, 0)
6240f0984d40SFabiano Rosas DO_SMLAX(SMLALTT, 2, 1, 1)
6241f0984d40SFabiano Rosas 
6242f0984d40SFabiano Rosas #undef DO_SMLAX
6243f0984d40SFabiano Rosas 
6244f0984d40SFabiano Rosas static bool op_smlawx(DisasContext *s, arg_rrrr *a, bool add, bool mt)
6245f0984d40SFabiano Rosas {
6246f0984d40SFabiano Rosas     TCGv_i32 t0, t1;
6247f0984d40SFabiano Rosas 
6248f0984d40SFabiano Rosas     if (!ENABLE_ARCH_5TE) {
6249f0984d40SFabiano Rosas         return false;
6250f0984d40SFabiano Rosas     }
6251f0984d40SFabiano Rosas 
6252f0984d40SFabiano Rosas     t0 = load_reg(s, a->rn);
6253f0984d40SFabiano Rosas     t1 = load_reg(s, a->rm);
6254f0984d40SFabiano Rosas     /*
6255f0984d40SFabiano Rosas      * Since the nominal result is product<47:16>, shift the 16-bit
6256f0984d40SFabiano Rosas      * input up by 16 bits, so that the result is at product<63:32>.
6257f0984d40SFabiano Rosas      */
6258f0984d40SFabiano Rosas     if (mt) {
6259f0984d40SFabiano Rosas         tcg_gen_andi_i32(t1, t1, 0xffff0000);
6260f0984d40SFabiano Rosas     } else {
6261f0984d40SFabiano Rosas         tcg_gen_shli_i32(t1, t1, 16);
6262f0984d40SFabiano Rosas     }
6263f0984d40SFabiano Rosas     tcg_gen_muls2_i32(t0, t1, t0, t1);
6264f0984d40SFabiano Rosas     tcg_temp_free_i32(t0);
6265f0984d40SFabiano Rosas     if (add) {
6266f0984d40SFabiano Rosas         t0 = load_reg(s, a->ra);
6267f0984d40SFabiano Rosas         gen_helper_add_setq(t1, cpu_env, t1, t0);
6268f0984d40SFabiano Rosas         tcg_temp_free_i32(t0);
6269f0984d40SFabiano Rosas     }
6270f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
6271f0984d40SFabiano Rosas     return true;
6272f0984d40SFabiano Rosas }
6273f0984d40SFabiano Rosas 
6274f0984d40SFabiano Rosas #define DO_SMLAWX(NAME, add, mt) \
6275f0984d40SFabiano Rosas static bool trans_##NAME(DisasContext *s, arg_rrrr *a)     \
6276f0984d40SFabiano Rosas {                                                          \
6277f0984d40SFabiano Rosas     return op_smlawx(s, a, add, mt);                       \
6278f0984d40SFabiano Rosas }
6279f0984d40SFabiano Rosas 
6280f0984d40SFabiano Rosas DO_SMLAWX(SMULWB, 0, 0)
6281f0984d40SFabiano Rosas DO_SMLAWX(SMULWT, 0, 1)
6282f0984d40SFabiano Rosas DO_SMLAWX(SMLAWB, 1, 0)
6283f0984d40SFabiano Rosas DO_SMLAWX(SMLAWT, 1, 1)
6284f0984d40SFabiano Rosas 
6285f0984d40SFabiano Rosas #undef DO_SMLAWX
6286f0984d40SFabiano Rosas 
6287f0984d40SFabiano Rosas /*
6288f0984d40SFabiano Rosas  * MSR (immediate) and hints
6289f0984d40SFabiano Rosas  */
6290f0984d40SFabiano Rosas 
6291f0984d40SFabiano Rosas static bool trans_YIELD(DisasContext *s, arg_YIELD *a)
6292f0984d40SFabiano Rosas {
6293f0984d40SFabiano Rosas     /*
6294f0984d40SFabiano Rosas      * When running single-threaded TCG code, use the helper to ensure that
6295f0984d40SFabiano Rosas      * the next round-robin scheduled vCPU gets a crack.  When running in
6296f0984d40SFabiano Rosas      * MTTCG we don't generate jumps to the helper as it won't affect the
6297f0984d40SFabiano Rosas      * scheduling of other vCPUs.
6298f0984d40SFabiano Rosas      */
6299f0984d40SFabiano Rosas     if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
6300f0984d40SFabiano Rosas         gen_update_pc(s, curr_insn_len(s));
6301f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_YIELD;
6302f0984d40SFabiano Rosas     }
6303f0984d40SFabiano Rosas     return true;
6304f0984d40SFabiano Rosas }
6305f0984d40SFabiano Rosas 
6306f0984d40SFabiano Rosas static bool trans_WFE(DisasContext *s, arg_WFE *a)
6307f0984d40SFabiano Rosas {
6308f0984d40SFabiano Rosas     /*
6309f0984d40SFabiano Rosas      * When running single-threaded TCG code, use the helper to ensure that
6310f0984d40SFabiano Rosas      * the next round-robin scheduled vCPU gets a crack.  In MTTCG mode we
6311f0984d40SFabiano Rosas      * just skip this instruction.  Currently the SEV/SEVL instructions,
6312f0984d40SFabiano Rosas      * which are *one* of many ways to wake the CPU from WFE, are not
6313f0984d40SFabiano Rosas      * implemented so we can't sleep like WFI does.
6314f0984d40SFabiano Rosas      */
6315f0984d40SFabiano Rosas     if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
6316f0984d40SFabiano Rosas         gen_update_pc(s, curr_insn_len(s));
6317f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_WFE;
6318f0984d40SFabiano Rosas     }
6319f0984d40SFabiano Rosas     return true;
6320f0984d40SFabiano Rosas }
6321f0984d40SFabiano Rosas 
6322f0984d40SFabiano Rosas static bool trans_WFI(DisasContext *s, arg_WFI *a)
6323f0984d40SFabiano Rosas {
6324f0984d40SFabiano Rosas     /* For WFI, halt the vCPU until an IRQ. */
6325f0984d40SFabiano Rosas     gen_update_pc(s, curr_insn_len(s));
6326f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_WFI;
6327f0984d40SFabiano Rosas     return true;
6328f0984d40SFabiano Rosas }
6329f0984d40SFabiano Rosas 
6330f0984d40SFabiano Rosas static bool trans_ESB(DisasContext *s, arg_ESB *a)
6331f0984d40SFabiano Rosas {
6332f0984d40SFabiano Rosas     /*
6333f0984d40SFabiano Rosas      * For M-profile, minimal-RAS ESB can be a NOP.
6334f0984d40SFabiano Rosas      * Without RAS, we must implement this as NOP.
6335f0984d40SFabiano Rosas      */
6336f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_M) && dc_isar_feature(aa32_ras, s)) {
6337f0984d40SFabiano Rosas         /*
6338f0984d40SFabiano Rosas          * QEMU does not have a source of physical SErrors,
6339f0984d40SFabiano Rosas          * so we are only concerned with virtual SErrors.
6340f0984d40SFabiano Rosas          * The pseudocode in the ARM for this case is
6341f0984d40SFabiano Rosas          *   if PSTATE.EL IN {EL0, EL1} && EL2Enabled() then
6342f0984d40SFabiano Rosas          *      AArch32.vESBOperation();
6343f0984d40SFabiano Rosas          * Most of the condition can be evaluated at translation time.
6344f0984d40SFabiano Rosas          * Test for EL2 present, and defer test for SEL2 to runtime.
6345f0984d40SFabiano Rosas          */
6346f0984d40SFabiano Rosas         if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) {
6347f0984d40SFabiano Rosas             gen_helper_vesb(cpu_env);
6348f0984d40SFabiano Rosas         }
6349f0984d40SFabiano Rosas     }
6350f0984d40SFabiano Rosas     return true;
6351f0984d40SFabiano Rosas }
6352f0984d40SFabiano Rosas 
6353f0984d40SFabiano Rosas static bool trans_NOP(DisasContext *s, arg_NOP *a)
6354f0984d40SFabiano Rosas {
6355f0984d40SFabiano Rosas     return true;
6356f0984d40SFabiano Rosas }
6357f0984d40SFabiano Rosas 
6358f0984d40SFabiano Rosas static bool trans_MSR_imm(DisasContext *s, arg_MSR_imm *a)
6359f0984d40SFabiano Rosas {
6360f0984d40SFabiano Rosas     uint32_t val = ror32(a->imm, a->rot * 2);
6361f0984d40SFabiano Rosas     uint32_t mask = msr_mask(s, a->mask, a->r);
6362f0984d40SFabiano Rosas 
6363f0984d40SFabiano Rosas     if (gen_set_psr_im(s, mask, a->r, val)) {
6364f0984d40SFabiano Rosas         unallocated_encoding(s);
6365f0984d40SFabiano Rosas     }
6366f0984d40SFabiano Rosas     return true;
6367f0984d40SFabiano Rosas }
6368f0984d40SFabiano Rosas 
6369f0984d40SFabiano Rosas /*
6370f0984d40SFabiano Rosas  * Cyclic Redundancy Check
6371f0984d40SFabiano Rosas  */
6372f0984d40SFabiano Rosas 
6373f0984d40SFabiano Rosas static bool op_crc32(DisasContext *s, arg_rrr *a, bool c, MemOp sz)
6374f0984d40SFabiano Rosas {
6375f0984d40SFabiano Rosas     TCGv_i32 t1, t2, t3;
6376f0984d40SFabiano Rosas 
6377f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_crc32, s)) {
6378f0984d40SFabiano Rosas         return false;
6379f0984d40SFabiano Rosas     }
6380f0984d40SFabiano Rosas 
6381f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
6382f0984d40SFabiano Rosas     t2 = load_reg(s, a->rm);
6383f0984d40SFabiano Rosas     switch (sz) {
6384f0984d40SFabiano Rosas     case MO_8:
6385f0984d40SFabiano Rosas         gen_uxtb(t2);
6386f0984d40SFabiano Rosas         break;
6387f0984d40SFabiano Rosas     case MO_16:
6388f0984d40SFabiano Rosas         gen_uxth(t2);
6389f0984d40SFabiano Rosas         break;
6390f0984d40SFabiano Rosas     case MO_32:
6391f0984d40SFabiano Rosas         break;
6392f0984d40SFabiano Rosas     default:
6393f0984d40SFabiano Rosas         g_assert_not_reached();
6394f0984d40SFabiano Rosas     }
6395f0984d40SFabiano Rosas     t3 = tcg_constant_i32(1 << sz);
6396f0984d40SFabiano Rosas     if (c) {
6397f0984d40SFabiano Rosas         gen_helper_crc32c(t1, t1, t2, t3);
6398f0984d40SFabiano Rosas     } else {
6399f0984d40SFabiano Rosas         gen_helper_crc32(t1, t1, t2, t3);
6400f0984d40SFabiano Rosas     }
6401f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
6402f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
6403f0984d40SFabiano Rosas     return true;
6404f0984d40SFabiano Rosas }
6405f0984d40SFabiano Rosas 
6406f0984d40SFabiano Rosas #define DO_CRC32(NAME, c, sz) \
6407f0984d40SFabiano Rosas static bool trans_##NAME(DisasContext *s, arg_rrr *a)  \
6408f0984d40SFabiano Rosas     { return op_crc32(s, a, c, sz); }
6409f0984d40SFabiano Rosas 
6410f0984d40SFabiano Rosas DO_CRC32(CRC32B, false, MO_8)
6411f0984d40SFabiano Rosas DO_CRC32(CRC32H, false, MO_16)
6412f0984d40SFabiano Rosas DO_CRC32(CRC32W, false, MO_32)
6413f0984d40SFabiano Rosas DO_CRC32(CRC32CB, true, MO_8)
6414f0984d40SFabiano Rosas DO_CRC32(CRC32CH, true, MO_16)
6415f0984d40SFabiano Rosas DO_CRC32(CRC32CW, true, MO_32)
6416f0984d40SFabiano Rosas 
6417f0984d40SFabiano Rosas #undef DO_CRC32
6418f0984d40SFabiano Rosas 
6419f0984d40SFabiano Rosas /*
6420f0984d40SFabiano Rosas  * Miscellaneous instructions
6421f0984d40SFabiano Rosas  */
6422f0984d40SFabiano Rosas 
6423f0984d40SFabiano Rosas static bool trans_MRS_bank(DisasContext *s, arg_MRS_bank *a)
6424f0984d40SFabiano Rosas {
6425f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M)) {
6426f0984d40SFabiano Rosas         return false;
6427f0984d40SFabiano Rosas     }
6428f0984d40SFabiano Rosas     gen_mrs_banked(s, a->r, a->sysm, a->rd);
6429f0984d40SFabiano Rosas     return true;
6430f0984d40SFabiano Rosas }
6431f0984d40SFabiano Rosas 
6432f0984d40SFabiano Rosas static bool trans_MSR_bank(DisasContext *s, arg_MSR_bank *a)
6433f0984d40SFabiano Rosas {
6434f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M)) {
6435f0984d40SFabiano Rosas         return false;
6436f0984d40SFabiano Rosas     }
6437f0984d40SFabiano Rosas     gen_msr_banked(s, a->r, a->sysm, a->rn);
6438f0984d40SFabiano Rosas     return true;
6439f0984d40SFabiano Rosas }
6440f0984d40SFabiano Rosas 
6441f0984d40SFabiano Rosas static bool trans_MRS_reg(DisasContext *s, arg_MRS_reg *a)
6442f0984d40SFabiano Rosas {
6443f0984d40SFabiano Rosas     TCGv_i32 tmp;
6444f0984d40SFabiano Rosas 
6445f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M)) {
6446f0984d40SFabiano Rosas         return false;
6447f0984d40SFabiano Rosas     }
6448f0984d40SFabiano Rosas     if (a->r) {
6449f0984d40SFabiano Rosas         if (IS_USER(s)) {
6450f0984d40SFabiano Rosas             unallocated_encoding(s);
6451f0984d40SFabiano Rosas             return true;
6452f0984d40SFabiano Rosas         }
6453f0984d40SFabiano Rosas         tmp = load_cpu_field(spsr);
6454f0984d40SFabiano Rosas     } else {
6455f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
6456f0984d40SFabiano Rosas         gen_helper_cpsr_read(tmp, cpu_env);
6457f0984d40SFabiano Rosas     }
6458f0984d40SFabiano Rosas     store_reg(s, a->rd, tmp);
6459f0984d40SFabiano Rosas     return true;
6460f0984d40SFabiano Rosas }
6461f0984d40SFabiano Rosas 
6462f0984d40SFabiano Rosas static bool trans_MSR_reg(DisasContext *s, arg_MSR_reg *a)
6463f0984d40SFabiano Rosas {
6464f0984d40SFabiano Rosas     TCGv_i32 tmp;
6465f0984d40SFabiano Rosas     uint32_t mask = msr_mask(s, a->mask, a->r);
6466f0984d40SFabiano Rosas 
6467f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M)) {
6468f0984d40SFabiano Rosas         return false;
6469f0984d40SFabiano Rosas     }
6470f0984d40SFabiano Rosas     tmp = load_reg(s, a->rn);
6471f0984d40SFabiano Rosas     if (gen_set_psr(s, mask, a->r, tmp)) {
6472f0984d40SFabiano Rosas         unallocated_encoding(s);
6473f0984d40SFabiano Rosas     }
6474f0984d40SFabiano Rosas     return true;
6475f0984d40SFabiano Rosas }
6476f0984d40SFabiano Rosas 
6477f0984d40SFabiano Rosas static bool trans_MRS_v7m(DisasContext *s, arg_MRS_v7m *a)
6478f0984d40SFabiano Rosas {
6479f0984d40SFabiano Rosas     TCGv_i32 tmp;
6480f0984d40SFabiano Rosas 
6481f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_M)) {
6482f0984d40SFabiano Rosas         return false;
6483f0984d40SFabiano Rosas     }
6484f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
6485f0984d40SFabiano Rosas     gen_helper_v7m_mrs(tmp, cpu_env, tcg_constant_i32(a->sysm));
6486f0984d40SFabiano Rosas     store_reg(s, a->rd, tmp);
6487f0984d40SFabiano Rosas     return true;
6488f0984d40SFabiano Rosas }
6489f0984d40SFabiano Rosas 
6490f0984d40SFabiano Rosas static bool trans_MSR_v7m(DisasContext *s, arg_MSR_v7m *a)
6491f0984d40SFabiano Rosas {
6492f0984d40SFabiano Rosas     TCGv_i32 addr, reg;
6493f0984d40SFabiano Rosas 
6494f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_M)) {
6495f0984d40SFabiano Rosas         return false;
6496f0984d40SFabiano Rosas     }
6497f0984d40SFabiano Rosas     addr = tcg_constant_i32((a->mask << 10) | a->sysm);
6498f0984d40SFabiano Rosas     reg = load_reg(s, a->rn);
6499f0984d40SFabiano Rosas     gen_helper_v7m_msr(cpu_env, addr, reg);
6500f0984d40SFabiano Rosas     tcg_temp_free_i32(reg);
6501f0984d40SFabiano Rosas     /* If we wrote to CONTROL, the EL might have changed */
6502f0984d40SFabiano Rosas     gen_rebuild_hflags(s, true);
6503f0984d40SFabiano Rosas     gen_lookup_tb(s);
6504f0984d40SFabiano Rosas     return true;
6505f0984d40SFabiano Rosas }
6506f0984d40SFabiano Rosas 
6507f0984d40SFabiano Rosas static bool trans_BX(DisasContext *s, arg_BX *a)
6508f0984d40SFabiano Rosas {
6509f0984d40SFabiano Rosas     if (!ENABLE_ARCH_4T) {
6510f0984d40SFabiano Rosas         return false;
6511f0984d40SFabiano Rosas     }
6512f0984d40SFabiano Rosas     gen_bx_excret(s, load_reg(s, a->rm));
6513f0984d40SFabiano Rosas     return true;
6514f0984d40SFabiano Rosas }
6515f0984d40SFabiano Rosas 
6516f0984d40SFabiano Rosas static bool trans_BXJ(DisasContext *s, arg_BXJ *a)
6517f0984d40SFabiano Rosas {
6518f0984d40SFabiano Rosas     if (!ENABLE_ARCH_5J || arm_dc_feature(s, ARM_FEATURE_M)) {
6519f0984d40SFabiano Rosas         return false;
6520f0984d40SFabiano Rosas     }
6521f0984d40SFabiano Rosas     /*
6522f0984d40SFabiano Rosas      * v7A allows BXJ to be trapped via HSTR.TJDBX. We don't waste a
6523f0984d40SFabiano Rosas      * TBFLAGS bit on a basically-never-happens case, so call a helper
6524f0984d40SFabiano Rosas      * function to check for the trap and raise the exception if needed
6525f0984d40SFabiano Rosas      * (passing it the register number for the syndrome value).
6526f0984d40SFabiano Rosas      * v8A doesn't have this HSTR bit.
6527f0984d40SFabiano Rosas      */
6528f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V8) &&
6529f0984d40SFabiano Rosas         arm_dc_feature(s, ARM_FEATURE_EL2) &&
6530f0984d40SFabiano Rosas         s->current_el < 2 && s->ns) {
6531f0984d40SFabiano Rosas         gen_helper_check_bxj_trap(cpu_env, tcg_constant_i32(a->rm));
6532f0984d40SFabiano Rosas     }
6533f0984d40SFabiano Rosas     /* Trivial implementation equivalent to bx.  */
6534f0984d40SFabiano Rosas     gen_bx(s, load_reg(s, a->rm));
6535f0984d40SFabiano Rosas     return true;
6536f0984d40SFabiano Rosas }
6537f0984d40SFabiano Rosas 
6538f0984d40SFabiano Rosas static bool trans_BLX_r(DisasContext *s, arg_BLX_r *a)
6539f0984d40SFabiano Rosas {
6540f0984d40SFabiano Rosas     TCGv_i32 tmp;
6541f0984d40SFabiano Rosas 
6542f0984d40SFabiano Rosas     if (!ENABLE_ARCH_5) {
6543f0984d40SFabiano Rosas         return false;
6544f0984d40SFabiano Rosas     }
6545f0984d40SFabiano Rosas     tmp = load_reg(s, a->rm);
6546f0984d40SFabiano Rosas     gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
6547f0984d40SFabiano Rosas     gen_bx(s, tmp);
6548f0984d40SFabiano Rosas     return true;
6549f0984d40SFabiano Rosas }
6550f0984d40SFabiano Rosas 
6551f0984d40SFabiano Rosas /*
6552f0984d40SFabiano Rosas  * BXNS/BLXNS: only exist for v8M with the security extensions,
6553f0984d40SFabiano Rosas  * and always UNDEF if NonSecure.  We don't implement these in
6554f0984d40SFabiano Rosas  * the user-only mode either (in theory you can use them from
6555f0984d40SFabiano Rosas  * Secure User mode but they are too tied in to system emulation).
6556f0984d40SFabiano Rosas  */
6557f0984d40SFabiano Rosas static bool trans_BXNS(DisasContext *s, arg_BXNS *a)
6558f0984d40SFabiano Rosas {
6559f0984d40SFabiano Rosas     if (!s->v8m_secure || IS_USER_ONLY) {
6560f0984d40SFabiano Rosas         unallocated_encoding(s);
6561f0984d40SFabiano Rosas     } else {
6562f0984d40SFabiano Rosas         gen_bxns(s, a->rm);
6563f0984d40SFabiano Rosas     }
6564f0984d40SFabiano Rosas     return true;
6565f0984d40SFabiano Rosas }
6566f0984d40SFabiano Rosas 
6567f0984d40SFabiano Rosas static bool trans_BLXNS(DisasContext *s, arg_BLXNS *a)
6568f0984d40SFabiano Rosas {
6569f0984d40SFabiano Rosas     if (!s->v8m_secure || IS_USER_ONLY) {
6570f0984d40SFabiano Rosas         unallocated_encoding(s);
6571f0984d40SFabiano Rosas     } else {
6572f0984d40SFabiano Rosas         gen_blxns(s, a->rm);
6573f0984d40SFabiano Rosas     }
6574f0984d40SFabiano Rosas     return true;
6575f0984d40SFabiano Rosas }
6576f0984d40SFabiano Rosas 
6577f0984d40SFabiano Rosas static bool trans_CLZ(DisasContext *s, arg_CLZ *a)
6578f0984d40SFabiano Rosas {
6579f0984d40SFabiano Rosas     TCGv_i32 tmp;
6580f0984d40SFabiano Rosas 
6581f0984d40SFabiano Rosas     if (!ENABLE_ARCH_5) {
6582f0984d40SFabiano Rosas         return false;
6583f0984d40SFabiano Rosas     }
6584f0984d40SFabiano Rosas     tmp = load_reg(s, a->rm);
6585f0984d40SFabiano Rosas     tcg_gen_clzi_i32(tmp, tmp, 32);
6586f0984d40SFabiano Rosas     store_reg(s, a->rd, tmp);
6587f0984d40SFabiano Rosas     return true;
6588f0984d40SFabiano Rosas }
6589f0984d40SFabiano Rosas 
6590f0984d40SFabiano Rosas static bool trans_ERET(DisasContext *s, arg_ERET *a)
6591f0984d40SFabiano Rosas {
6592f0984d40SFabiano Rosas     TCGv_i32 tmp;
6593f0984d40SFabiano Rosas 
6594f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V7VE)) {
6595f0984d40SFabiano Rosas         return false;
6596f0984d40SFabiano Rosas     }
6597f0984d40SFabiano Rosas     if (IS_USER(s)) {
6598f0984d40SFabiano Rosas         unallocated_encoding(s);
6599f0984d40SFabiano Rosas         return true;
6600f0984d40SFabiano Rosas     }
6601f0984d40SFabiano Rosas     if (s->current_el == 2) {
6602f0984d40SFabiano Rosas         /* ERET from Hyp uses ELR_Hyp, not LR */
6603f0984d40SFabiano Rosas         tmp = load_cpu_field(elr_el[2]);
6604f0984d40SFabiano Rosas     } else {
6605f0984d40SFabiano Rosas         tmp = load_reg(s, 14);
6606f0984d40SFabiano Rosas     }
6607f0984d40SFabiano Rosas     gen_exception_return(s, tmp);
6608f0984d40SFabiano Rosas     return true;
6609f0984d40SFabiano Rosas }
6610f0984d40SFabiano Rosas 
6611f0984d40SFabiano Rosas static bool trans_HLT(DisasContext *s, arg_HLT *a)
6612f0984d40SFabiano Rosas {
6613f0984d40SFabiano Rosas     gen_hlt(s, a->imm);
6614f0984d40SFabiano Rosas     return true;
6615f0984d40SFabiano Rosas }
6616f0984d40SFabiano Rosas 
6617f0984d40SFabiano Rosas static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
6618f0984d40SFabiano Rosas {
6619f0984d40SFabiano Rosas     if (!ENABLE_ARCH_5) {
6620f0984d40SFabiano Rosas         return false;
6621f0984d40SFabiano Rosas     }
6622f0984d40SFabiano Rosas     /* BKPT is OK with ECI set and leaves it untouched */
6623f0984d40SFabiano Rosas     s->eci_handled = true;
6624f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M) &&
6625f0984d40SFabiano Rosas         semihosting_enabled(s->current_el == 0) &&
6626f0984d40SFabiano Rosas         (a->imm == 0xab)) {
6627f0984d40SFabiano Rosas         gen_exception_internal_insn(s, EXCP_SEMIHOST);
6628f0984d40SFabiano Rosas     } else {
6629f0984d40SFabiano Rosas         gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
6630f0984d40SFabiano Rosas     }
6631f0984d40SFabiano Rosas     return true;
6632f0984d40SFabiano Rosas }
6633f0984d40SFabiano Rosas 
6634f0984d40SFabiano Rosas static bool trans_HVC(DisasContext *s, arg_HVC *a)
6635f0984d40SFabiano Rosas {
6636f0984d40SFabiano Rosas     if (!ENABLE_ARCH_7 || arm_dc_feature(s, ARM_FEATURE_M)) {
6637f0984d40SFabiano Rosas         return false;
6638f0984d40SFabiano Rosas     }
6639f0984d40SFabiano Rosas     if (IS_USER(s)) {
6640f0984d40SFabiano Rosas         unallocated_encoding(s);
6641f0984d40SFabiano Rosas     } else {
6642f0984d40SFabiano Rosas         gen_hvc(s, a->imm);
6643f0984d40SFabiano Rosas     }
6644f0984d40SFabiano Rosas     return true;
6645f0984d40SFabiano Rosas }
6646f0984d40SFabiano Rosas 
6647f0984d40SFabiano Rosas static bool trans_SMC(DisasContext *s, arg_SMC *a)
6648f0984d40SFabiano Rosas {
6649f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6K || arm_dc_feature(s, ARM_FEATURE_M)) {
6650f0984d40SFabiano Rosas         return false;
6651f0984d40SFabiano Rosas     }
6652f0984d40SFabiano Rosas     if (IS_USER(s)) {
6653f0984d40SFabiano Rosas         unallocated_encoding(s);
6654f0984d40SFabiano Rosas     } else {
6655f0984d40SFabiano Rosas         gen_smc(s);
6656f0984d40SFabiano Rosas     }
6657f0984d40SFabiano Rosas     return true;
6658f0984d40SFabiano Rosas }
6659f0984d40SFabiano Rosas 
6660f0984d40SFabiano Rosas static bool trans_SG(DisasContext *s, arg_SG *a)
6661f0984d40SFabiano Rosas {
6662f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_M) ||
6663f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_V8)) {
6664f0984d40SFabiano Rosas         return false;
6665f0984d40SFabiano Rosas     }
6666f0984d40SFabiano Rosas     /*
6667f0984d40SFabiano Rosas      * SG (v8M only)
6668f0984d40SFabiano Rosas      * The bulk of the behaviour for this instruction is implemented
6669f0984d40SFabiano Rosas      * in v7m_handle_execute_nsc(), which deals with the insn when
6670f0984d40SFabiano Rosas      * it is executed by a CPU in non-secure state from memory
6671f0984d40SFabiano Rosas      * which is Secure & NonSecure-Callable.
6672f0984d40SFabiano Rosas      * Here we only need to handle the remaining cases:
6673f0984d40SFabiano Rosas      *  * in NS memory (including the "security extension not
6674f0984d40SFabiano Rosas      *    implemented" case) : NOP
6675f0984d40SFabiano Rosas      *  * in S memory but CPU already secure (clear IT bits)
6676f0984d40SFabiano Rosas      * We know that the attribute for the memory this insn is
6677f0984d40SFabiano Rosas      * in must match the current CPU state, because otherwise
6678f0984d40SFabiano Rosas      * get_phys_addr_pmsav8 would have generated an exception.
6679f0984d40SFabiano Rosas      */
6680f0984d40SFabiano Rosas     if (s->v8m_secure) {
6681f0984d40SFabiano Rosas         /* Like the IT insn, we don't need to generate any code */
6682f0984d40SFabiano Rosas         s->condexec_cond = 0;
6683f0984d40SFabiano Rosas         s->condexec_mask = 0;
6684f0984d40SFabiano Rosas     }
6685f0984d40SFabiano Rosas     return true;
6686f0984d40SFabiano Rosas }
6687f0984d40SFabiano Rosas 
6688f0984d40SFabiano Rosas static bool trans_TT(DisasContext *s, arg_TT *a)
6689f0984d40SFabiano Rosas {
6690f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
6691f0984d40SFabiano Rosas 
6692f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_M) ||
6693f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_V8)) {
6694f0984d40SFabiano Rosas         return false;
6695f0984d40SFabiano Rosas     }
6696f0984d40SFabiano Rosas     if (a->rd == 13 || a->rd == 15 || a->rn == 15) {
6697f0984d40SFabiano Rosas         /* We UNDEF for these UNPREDICTABLE cases */
6698f0984d40SFabiano Rosas         unallocated_encoding(s);
6699f0984d40SFabiano Rosas         return true;
6700f0984d40SFabiano Rosas     }
6701f0984d40SFabiano Rosas     if (a->A && !s->v8m_secure) {
6702f0984d40SFabiano Rosas         /* This case is UNDEFINED.  */
6703f0984d40SFabiano Rosas         unallocated_encoding(s);
6704f0984d40SFabiano Rosas         return true;
6705f0984d40SFabiano Rosas     }
6706f0984d40SFabiano Rosas 
6707f0984d40SFabiano Rosas     addr = load_reg(s, a->rn);
6708f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
6709f0984d40SFabiano Rosas     gen_helper_v7m_tt(tmp, cpu_env, addr, tcg_constant_i32((a->A << 1) | a->T));
6710f0984d40SFabiano Rosas     tcg_temp_free_i32(addr);
6711f0984d40SFabiano Rosas     store_reg(s, a->rd, tmp);
6712f0984d40SFabiano Rosas     return true;
6713f0984d40SFabiano Rosas }
6714f0984d40SFabiano Rosas 
6715f0984d40SFabiano Rosas /*
6716f0984d40SFabiano Rosas  * Load/store register index
6717f0984d40SFabiano Rosas  */
6718f0984d40SFabiano Rosas 
6719f0984d40SFabiano Rosas static ISSInfo make_issinfo(DisasContext *s, int rd, bool p, bool w)
6720f0984d40SFabiano Rosas {
6721f0984d40SFabiano Rosas     ISSInfo ret;
6722f0984d40SFabiano Rosas 
6723f0984d40SFabiano Rosas     /* ISS not valid if writeback */
6724f0984d40SFabiano Rosas     if (p && !w) {
6725f0984d40SFabiano Rosas         ret = rd;
6726f0984d40SFabiano Rosas         if (curr_insn_len(s) == 2) {
6727f0984d40SFabiano Rosas             ret |= ISSIs16Bit;
6728f0984d40SFabiano Rosas         }
6729f0984d40SFabiano Rosas     } else {
6730f0984d40SFabiano Rosas         ret = ISSInvalid;
6731f0984d40SFabiano Rosas     }
6732f0984d40SFabiano Rosas     return ret;
6733f0984d40SFabiano Rosas }
6734f0984d40SFabiano Rosas 
6735f0984d40SFabiano Rosas static TCGv_i32 op_addr_rr_pre(DisasContext *s, arg_ldst_rr *a)
6736f0984d40SFabiano Rosas {
6737f0984d40SFabiano Rosas     TCGv_i32 addr = load_reg(s, a->rn);
6738f0984d40SFabiano Rosas 
6739f0984d40SFabiano Rosas     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
6740f0984d40SFabiano Rosas         gen_helper_v8m_stackcheck(cpu_env, addr);
6741f0984d40SFabiano Rosas     }
6742f0984d40SFabiano Rosas 
6743f0984d40SFabiano Rosas     if (a->p) {
6744f0984d40SFabiano Rosas         TCGv_i32 ofs = load_reg(s, a->rm);
6745f0984d40SFabiano Rosas         gen_arm_shift_im(ofs, a->shtype, a->shimm, 0);
6746f0984d40SFabiano Rosas         if (a->u) {
6747f0984d40SFabiano Rosas             tcg_gen_add_i32(addr, addr, ofs);
6748f0984d40SFabiano Rosas         } else {
6749f0984d40SFabiano Rosas             tcg_gen_sub_i32(addr, addr, ofs);
6750f0984d40SFabiano Rosas         }
6751f0984d40SFabiano Rosas         tcg_temp_free_i32(ofs);
6752f0984d40SFabiano Rosas     }
6753f0984d40SFabiano Rosas     return addr;
6754f0984d40SFabiano Rosas }
6755f0984d40SFabiano Rosas 
6756f0984d40SFabiano Rosas static void op_addr_rr_post(DisasContext *s, arg_ldst_rr *a,
6757f0984d40SFabiano Rosas                             TCGv_i32 addr, int address_offset)
6758f0984d40SFabiano Rosas {
6759f0984d40SFabiano Rosas     if (!a->p) {
6760f0984d40SFabiano Rosas         TCGv_i32 ofs = load_reg(s, a->rm);
6761f0984d40SFabiano Rosas         gen_arm_shift_im(ofs, a->shtype, a->shimm, 0);
6762f0984d40SFabiano Rosas         if (a->u) {
6763f0984d40SFabiano Rosas             tcg_gen_add_i32(addr, addr, ofs);
6764f0984d40SFabiano Rosas         } else {
6765f0984d40SFabiano Rosas             tcg_gen_sub_i32(addr, addr, ofs);
6766f0984d40SFabiano Rosas         }
6767f0984d40SFabiano Rosas         tcg_temp_free_i32(ofs);
6768f0984d40SFabiano Rosas     } else if (!a->w) {
6769f0984d40SFabiano Rosas         tcg_temp_free_i32(addr);
6770f0984d40SFabiano Rosas         return;
6771f0984d40SFabiano Rosas     }
6772f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, address_offset);
6773f0984d40SFabiano Rosas     store_reg(s, a->rn, addr);
6774f0984d40SFabiano Rosas }
6775f0984d40SFabiano Rosas 
6776f0984d40SFabiano Rosas static bool op_load_rr(DisasContext *s, arg_ldst_rr *a,
6777f0984d40SFabiano Rosas                        MemOp mop, int mem_idx)
6778f0984d40SFabiano Rosas {
6779f0984d40SFabiano Rosas     ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w);
6780f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
6781f0984d40SFabiano Rosas 
6782f0984d40SFabiano Rosas     addr = op_addr_rr_pre(s, a);
6783f0984d40SFabiano Rosas 
6784f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
6785f0984d40SFabiano Rosas     gen_aa32_ld_i32(s, tmp, addr, mem_idx, mop);
6786f0984d40SFabiano Rosas     disas_set_da_iss(s, mop, issinfo);
6787f0984d40SFabiano Rosas 
6788f0984d40SFabiano Rosas     /*
6789f0984d40SFabiano Rosas      * Perform base writeback before the loaded value to
6790f0984d40SFabiano Rosas      * ensure correct behavior with overlapping index registers.
6791f0984d40SFabiano Rosas      */
6792f0984d40SFabiano Rosas     op_addr_rr_post(s, a, addr, 0);
6793f0984d40SFabiano Rosas     store_reg_from_load(s, a->rt, tmp);
6794f0984d40SFabiano Rosas     return true;
6795f0984d40SFabiano Rosas }
6796f0984d40SFabiano Rosas 
6797f0984d40SFabiano Rosas static bool op_store_rr(DisasContext *s, arg_ldst_rr *a,
6798f0984d40SFabiano Rosas                         MemOp mop, int mem_idx)
6799f0984d40SFabiano Rosas {
6800f0984d40SFabiano Rosas     ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w) | ISSIsWrite;
6801f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
6802f0984d40SFabiano Rosas 
6803f0984d40SFabiano Rosas     /*
6804f0984d40SFabiano Rosas      * In Thumb encodings of stores Rn=1111 is UNDEF; for Arm it
6805f0984d40SFabiano Rosas      * is either UNPREDICTABLE or has defined behaviour
6806f0984d40SFabiano Rosas      */
6807f0984d40SFabiano Rosas     if (s->thumb && a->rn == 15) {
6808f0984d40SFabiano Rosas         return false;
6809f0984d40SFabiano Rosas     }
6810f0984d40SFabiano Rosas 
6811f0984d40SFabiano Rosas     addr = op_addr_rr_pre(s, a);
6812f0984d40SFabiano Rosas 
6813f0984d40SFabiano Rosas     tmp = load_reg(s, a->rt);
6814f0984d40SFabiano Rosas     gen_aa32_st_i32(s, tmp, addr, mem_idx, mop);
6815f0984d40SFabiano Rosas     disas_set_da_iss(s, mop, issinfo);
6816f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
6817f0984d40SFabiano Rosas 
6818f0984d40SFabiano Rosas     op_addr_rr_post(s, a, addr, 0);
6819f0984d40SFabiano Rosas     return true;
6820f0984d40SFabiano Rosas }
6821f0984d40SFabiano Rosas 
6822f0984d40SFabiano Rosas static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a)
6823f0984d40SFabiano Rosas {
6824f0984d40SFabiano Rosas     int mem_idx = get_mem_index(s);
6825f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
6826f0984d40SFabiano Rosas 
6827f0984d40SFabiano Rosas     if (!ENABLE_ARCH_5TE) {
6828f0984d40SFabiano Rosas         return false;
6829f0984d40SFabiano Rosas     }
6830f0984d40SFabiano Rosas     if (a->rt & 1) {
6831f0984d40SFabiano Rosas         unallocated_encoding(s);
6832f0984d40SFabiano Rosas         return true;
6833f0984d40SFabiano Rosas     }
6834f0984d40SFabiano Rosas     addr = op_addr_rr_pre(s, a);
6835f0984d40SFabiano Rosas 
6836f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
6837f0984d40SFabiano Rosas     gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
6838f0984d40SFabiano Rosas     store_reg(s, a->rt, tmp);
6839f0984d40SFabiano Rosas 
6840f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, 4);
6841f0984d40SFabiano Rosas 
6842f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
6843f0984d40SFabiano Rosas     gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
6844f0984d40SFabiano Rosas     store_reg(s, a->rt + 1, tmp);
6845f0984d40SFabiano Rosas 
6846f0984d40SFabiano Rosas     /* LDRD w/ base writeback is undefined if the registers overlap.  */
6847f0984d40SFabiano Rosas     op_addr_rr_post(s, a, addr, -4);
6848f0984d40SFabiano Rosas     return true;
6849f0984d40SFabiano Rosas }
6850f0984d40SFabiano Rosas 
6851f0984d40SFabiano Rosas static bool trans_STRD_rr(DisasContext *s, arg_ldst_rr *a)
6852f0984d40SFabiano Rosas {
6853f0984d40SFabiano Rosas     int mem_idx = get_mem_index(s);
6854f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
6855f0984d40SFabiano Rosas 
6856f0984d40SFabiano Rosas     if (!ENABLE_ARCH_5TE) {
6857f0984d40SFabiano Rosas         return false;
6858f0984d40SFabiano Rosas     }
6859f0984d40SFabiano Rosas     if (a->rt & 1) {
6860f0984d40SFabiano Rosas         unallocated_encoding(s);
6861f0984d40SFabiano Rosas         return true;
6862f0984d40SFabiano Rosas     }
6863f0984d40SFabiano Rosas     addr = op_addr_rr_pre(s, a);
6864f0984d40SFabiano Rosas 
6865f0984d40SFabiano Rosas     tmp = load_reg(s, a->rt);
6866f0984d40SFabiano Rosas     gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
6867f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
6868f0984d40SFabiano Rosas 
6869f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, 4);
6870f0984d40SFabiano Rosas 
6871f0984d40SFabiano Rosas     tmp = load_reg(s, a->rt + 1);
6872f0984d40SFabiano Rosas     gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
6873f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
6874f0984d40SFabiano Rosas 
6875f0984d40SFabiano Rosas     op_addr_rr_post(s, a, addr, -4);
6876f0984d40SFabiano Rosas     return true;
6877f0984d40SFabiano Rosas }
6878f0984d40SFabiano Rosas 
6879f0984d40SFabiano Rosas /*
6880f0984d40SFabiano Rosas  * Load/store immediate index
6881f0984d40SFabiano Rosas  */
6882f0984d40SFabiano Rosas 
6883f0984d40SFabiano Rosas static TCGv_i32 op_addr_ri_pre(DisasContext *s, arg_ldst_ri *a)
6884f0984d40SFabiano Rosas {
6885f0984d40SFabiano Rosas     int ofs = a->imm;
6886f0984d40SFabiano Rosas 
6887f0984d40SFabiano Rosas     if (!a->u) {
6888f0984d40SFabiano Rosas         ofs = -ofs;
6889f0984d40SFabiano Rosas     }
6890f0984d40SFabiano Rosas 
6891f0984d40SFabiano Rosas     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
6892f0984d40SFabiano Rosas         /*
6893f0984d40SFabiano Rosas          * Stackcheck. Here we know 'addr' is the current SP;
6894f0984d40SFabiano Rosas          * U is set if we're moving SP up, else down. It is
6895f0984d40SFabiano Rosas          * UNKNOWN whether the limit check triggers when SP starts
6896f0984d40SFabiano Rosas          * below the limit and ends up above it; we chose to do so.
6897f0984d40SFabiano Rosas          */
6898f0984d40SFabiano Rosas         if (!a->u) {
6899f0984d40SFabiano Rosas             TCGv_i32 newsp = tcg_temp_new_i32();
6900f0984d40SFabiano Rosas             tcg_gen_addi_i32(newsp, cpu_R[13], ofs);
6901f0984d40SFabiano Rosas             gen_helper_v8m_stackcheck(cpu_env, newsp);
6902f0984d40SFabiano Rosas             tcg_temp_free_i32(newsp);
6903f0984d40SFabiano Rosas         } else {
6904f0984d40SFabiano Rosas             gen_helper_v8m_stackcheck(cpu_env, cpu_R[13]);
6905f0984d40SFabiano Rosas         }
6906f0984d40SFabiano Rosas     }
6907f0984d40SFabiano Rosas 
6908f0984d40SFabiano Rosas     return add_reg_for_lit(s, a->rn, a->p ? ofs : 0);
6909f0984d40SFabiano Rosas }
6910f0984d40SFabiano Rosas 
6911f0984d40SFabiano Rosas static void op_addr_ri_post(DisasContext *s, arg_ldst_ri *a,
6912f0984d40SFabiano Rosas                             TCGv_i32 addr, int address_offset)
6913f0984d40SFabiano Rosas {
6914f0984d40SFabiano Rosas     if (!a->p) {
6915f0984d40SFabiano Rosas         if (a->u) {
6916f0984d40SFabiano Rosas             address_offset += a->imm;
6917f0984d40SFabiano Rosas         } else {
6918f0984d40SFabiano Rosas             address_offset -= a->imm;
6919f0984d40SFabiano Rosas         }
6920f0984d40SFabiano Rosas     } else if (!a->w) {
6921f0984d40SFabiano Rosas         tcg_temp_free_i32(addr);
6922f0984d40SFabiano Rosas         return;
6923f0984d40SFabiano Rosas     }
6924f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, address_offset);
6925f0984d40SFabiano Rosas     store_reg(s, a->rn, addr);
6926f0984d40SFabiano Rosas }
6927f0984d40SFabiano Rosas 
6928f0984d40SFabiano Rosas static bool op_load_ri(DisasContext *s, arg_ldst_ri *a,
6929f0984d40SFabiano Rosas                        MemOp mop, int mem_idx)
6930f0984d40SFabiano Rosas {
6931f0984d40SFabiano Rosas     ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w);
6932f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
6933f0984d40SFabiano Rosas 
6934f0984d40SFabiano Rosas     addr = op_addr_ri_pre(s, a);
6935f0984d40SFabiano Rosas 
6936f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
6937f0984d40SFabiano Rosas     gen_aa32_ld_i32(s, tmp, addr, mem_idx, mop);
6938f0984d40SFabiano Rosas     disas_set_da_iss(s, mop, issinfo);
6939f0984d40SFabiano Rosas 
6940f0984d40SFabiano Rosas     /*
6941f0984d40SFabiano Rosas      * Perform base writeback before the loaded value to
6942f0984d40SFabiano Rosas      * ensure correct behavior with overlapping index registers.
6943f0984d40SFabiano Rosas      */
6944f0984d40SFabiano Rosas     op_addr_ri_post(s, a, addr, 0);
6945f0984d40SFabiano Rosas     store_reg_from_load(s, a->rt, tmp);
6946f0984d40SFabiano Rosas     return true;
6947f0984d40SFabiano Rosas }
6948f0984d40SFabiano Rosas 
6949f0984d40SFabiano Rosas static bool op_store_ri(DisasContext *s, arg_ldst_ri *a,
6950f0984d40SFabiano Rosas                         MemOp mop, int mem_idx)
6951f0984d40SFabiano Rosas {
6952f0984d40SFabiano Rosas     ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w) | ISSIsWrite;
6953f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
6954f0984d40SFabiano Rosas 
6955f0984d40SFabiano Rosas     /*
6956f0984d40SFabiano Rosas      * In Thumb encodings of stores Rn=1111 is UNDEF; for Arm it
6957f0984d40SFabiano Rosas      * is either UNPREDICTABLE or has defined behaviour
6958f0984d40SFabiano Rosas      */
6959f0984d40SFabiano Rosas     if (s->thumb && a->rn == 15) {
6960f0984d40SFabiano Rosas         return false;
6961f0984d40SFabiano Rosas     }
6962f0984d40SFabiano Rosas 
6963f0984d40SFabiano Rosas     addr = op_addr_ri_pre(s, a);
6964f0984d40SFabiano Rosas 
6965f0984d40SFabiano Rosas     tmp = load_reg(s, a->rt);
6966f0984d40SFabiano Rosas     gen_aa32_st_i32(s, tmp, addr, mem_idx, mop);
6967f0984d40SFabiano Rosas     disas_set_da_iss(s, mop, issinfo);
6968f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
6969f0984d40SFabiano Rosas 
6970f0984d40SFabiano Rosas     op_addr_ri_post(s, a, addr, 0);
6971f0984d40SFabiano Rosas     return true;
6972f0984d40SFabiano Rosas }
6973f0984d40SFabiano Rosas 
6974f0984d40SFabiano Rosas static bool op_ldrd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
6975f0984d40SFabiano Rosas {
6976f0984d40SFabiano Rosas     int mem_idx = get_mem_index(s);
6977f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
6978f0984d40SFabiano Rosas 
6979f0984d40SFabiano Rosas     addr = op_addr_ri_pre(s, a);
6980f0984d40SFabiano Rosas 
6981f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
6982f0984d40SFabiano Rosas     gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
6983f0984d40SFabiano Rosas     store_reg(s, a->rt, tmp);
6984f0984d40SFabiano Rosas 
6985f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, 4);
6986f0984d40SFabiano Rosas 
6987f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
6988f0984d40SFabiano Rosas     gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
6989f0984d40SFabiano Rosas     store_reg(s, rt2, tmp);
6990f0984d40SFabiano Rosas 
6991f0984d40SFabiano Rosas     /* LDRD w/ base writeback is undefined if the registers overlap.  */
6992f0984d40SFabiano Rosas     op_addr_ri_post(s, a, addr, -4);
6993f0984d40SFabiano Rosas     return true;
6994f0984d40SFabiano Rosas }
6995f0984d40SFabiano Rosas 
6996f0984d40SFabiano Rosas static bool trans_LDRD_ri_a32(DisasContext *s, arg_ldst_ri *a)
6997f0984d40SFabiano Rosas {
6998f0984d40SFabiano Rosas     if (!ENABLE_ARCH_5TE || (a->rt & 1)) {
6999f0984d40SFabiano Rosas         return false;
7000f0984d40SFabiano Rosas     }
7001f0984d40SFabiano Rosas     return op_ldrd_ri(s, a, a->rt + 1);
7002f0984d40SFabiano Rosas }
7003f0984d40SFabiano Rosas 
7004f0984d40SFabiano Rosas static bool trans_LDRD_ri_t32(DisasContext *s, arg_ldst_ri2 *a)
7005f0984d40SFabiano Rosas {
7006f0984d40SFabiano Rosas     arg_ldst_ri b = {
7007f0984d40SFabiano Rosas         .u = a->u, .w = a->w, .p = a->p,
7008f0984d40SFabiano Rosas         .rn = a->rn, .rt = a->rt, .imm = a->imm
7009f0984d40SFabiano Rosas     };
7010f0984d40SFabiano Rosas     return op_ldrd_ri(s, &b, a->rt2);
7011f0984d40SFabiano Rosas }
7012f0984d40SFabiano Rosas 
7013f0984d40SFabiano Rosas static bool op_strd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
7014f0984d40SFabiano Rosas {
7015f0984d40SFabiano Rosas     int mem_idx = get_mem_index(s);
7016f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
7017f0984d40SFabiano Rosas 
7018f0984d40SFabiano Rosas     addr = op_addr_ri_pre(s, a);
7019f0984d40SFabiano Rosas 
7020f0984d40SFabiano Rosas     tmp = load_reg(s, a->rt);
7021f0984d40SFabiano Rosas     gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
7022f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
7023f0984d40SFabiano Rosas 
7024f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, 4);
7025f0984d40SFabiano Rosas 
7026f0984d40SFabiano Rosas     tmp = load_reg(s, rt2);
7027f0984d40SFabiano Rosas     gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
7028f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
7029f0984d40SFabiano Rosas 
7030f0984d40SFabiano Rosas     op_addr_ri_post(s, a, addr, -4);
7031f0984d40SFabiano Rosas     return true;
7032f0984d40SFabiano Rosas }
7033f0984d40SFabiano Rosas 
7034f0984d40SFabiano Rosas static bool trans_STRD_ri_a32(DisasContext *s, arg_ldst_ri *a)
7035f0984d40SFabiano Rosas {
7036f0984d40SFabiano Rosas     if (!ENABLE_ARCH_5TE || (a->rt & 1)) {
7037f0984d40SFabiano Rosas         return false;
7038f0984d40SFabiano Rosas     }
7039f0984d40SFabiano Rosas     return op_strd_ri(s, a, a->rt + 1);
7040f0984d40SFabiano Rosas }
7041f0984d40SFabiano Rosas 
7042f0984d40SFabiano Rosas static bool trans_STRD_ri_t32(DisasContext *s, arg_ldst_ri2 *a)
7043f0984d40SFabiano Rosas {
7044f0984d40SFabiano Rosas     arg_ldst_ri b = {
7045f0984d40SFabiano Rosas         .u = a->u, .w = a->w, .p = a->p,
7046f0984d40SFabiano Rosas         .rn = a->rn, .rt = a->rt, .imm = a->imm
7047f0984d40SFabiano Rosas     };
7048f0984d40SFabiano Rosas     return op_strd_ri(s, &b, a->rt2);
7049f0984d40SFabiano Rosas }
7050f0984d40SFabiano Rosas 
7051f0984d40SFabiano Rosas #define DO_LDST(NAME, WHICH, MEMOP) \
7052f0984d40SFabiano Rosas static bool trans_##NAME##_ri(DisasContext *s, arg_ldst_ri *a)        \
7053f0984d40SFabiano Rosas {                                                                     \
7054f0984d40SFabiano Rosas     return op_##WHICH##_ri(s, a, MEMOP, get_mem_index(s));            \
7055f0984d40SFabiano Rosas }                                                                     \
7056f0984d40SFabiano Rosas static bool trans_##NAME##T_ri(DisasContext *s, arg_ldst_ri *a)       \
7057f0984d40SFabiano Rosas {                                                                     \
7058f0984d40SFabiano Rosas     return op_##WHICH##_ri(s, a, MEMOP, get_a32_user_mem_index(s));   \
7059f0984d40SFabiano Rosas }                                                                     \
7060f0984d40SFabiano Rosas static bool trans_##NAME##_rr(DisasContext *s, arg_ldst_rr *a)        \
7061f0984d40SFabiano Rosas {                                                                     \
7062f0984d40SFabiano Rosas     return op_##WHICH##_rr(s, a, MEMOP, get_mem_index(s));            \
7063f0984d40SFabiano Rosas }                                                                     \
7064f0984d40SFabiano Rosas static bool trans_##NAME##T_rr(DisasContext *s, arg_ldst_rr *a)       \
7065f0984d40SFabiano Rosas {                                                                     \
7066f0984d40SFabiano Rosas     return op_##WHICH##_rr(s, a, MEMOP, get_a32_user_mem_index(s));   \
7067f0984d40SFabiano Rosas }
7068f0984d40SFabiano Rosas 
7069f0984d40SFabiano Rosas DO_LDST(LDR, load, MO_UL)
7070f0984d40SFabiano Rosas DO_LDST(LDRB, load, MO_UB)
7071f0984d40SFabiano Rosas DO_LDST(LDRH, load, MO_UW)
7072f0984d40SFabiano Rosas DO_LDST(LDRSB, load, MO_SB)
7073f0984d40SFabiano Rosas DO_LDST(LDRSH, load, MO_SW)
7074f0984d40SFabiano Rosas 
7075f0984d40SFabiano Rosas DO_LDST(STR, store, MO_UL)
7076f0984d40SFabiano Rosas DO_LDST(STRB, store, MO_UB)
7077f0984d40SFabiano Rosas DO_LDST(STRH, store, MO_UW)
7078f0984d40SFabiano Rosas 
7079f0984d40SFabiano Rosas #undef DO_LDST
7080f0984d40SFabiano Rosas 
7081f0984d40SFabiano Rosas /*
7082f0984d40SFabiano Rosas  * Synchronization primitives
7083f0984d40SFabiano Rosas  */
7084f0984d40SFabiano Rosas 
7085f0984d40SFabiano Rosas static bool op_swp(DisasContext *s, arg_SWP *a, MemOp opc)
7086f0984d40SFabiano Rosas {
7087f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
7088f0984d40SFabiano Rosas     TCGv taddr;
7089f0984d40SFabiano Rosas 
7090f0984d40SFabiano Rosas     opc |= s->be_data;
7091f0984d40SFabiano Rosas     addr = load_reg(s, a->rn);
7092f0984d40SFabiano Rosas     taddr = gen_aa32_addr(s, addr, opc);
7093f0984d40SFabiano Rosas     tcg_temp_free_i32(addr);
7094f0984d40SFabiano Rosas 
7095f0984d40SFabiano Rosas     tmp = load_reg(s, a->rt2);
7096f0984d40SFabiano Rosas     tcg_gen_atomic_xchg_i32(tmp, taddr, tmp, get_mem_index(s), opc);
7097f0984d40SFabiano Rosas     tcg_temp_free(taddr);
7098f0984d40SFabiano Rosas 
7099f0984d40SFabiano Rosas     store_reg(s, a->rt, tmp);
7100f0984d40SFabiano Rosas     return true;
7101f0984d40SFabiano Rosas }
7102f0984d40SFabiano Rosas 
7103f0984d40SFabiano Rosas static bool trans_SWP(DisasContext *s, arg_SWP *a)
7104f0984d40SFabiano Rosas {
7105f0984d40SFabiano Rosas     return op_swp(s, a, MO_UL | MO_ALIGN);
7106f0984d40SFabiano Rosas }
7107f0984d40SFabiano Rosas 
7108f0984d40SFabiano Rosas static bool trans_SWPB(DisasContext *s, arg_SWP *a)
7109f0984d40SFabiano Rosas {
7110f0984d40SFabiano Rosas     return op_swp(s, a, MO_UB);
7111f0984d40SFabiano Rosas }
7112f0984d40SFabiano Rosas 
7113f0984d40SFabiano Rosas /*
7114f0984d40SFabiano Rosas  * Load/Store Exclusive and Load-Acquire/Store-Release
7115f0984d40SFabiano Rosas  */
7116f0984d40SFabiano Rosas 
7117f0984d40SFabiano Rosas static bool op_strex(DisasContext *s, arg_STREX *a, MemOp mop, bool rel)
7118f0984d40SFabiano Rosas {
7119f0984d40SFabiano Rosas     TCGv_i32 addr;
7120f0984d40SFabiano Rosas     /* Some cases stopped being UNPREDICTABLE in v8A (but not v8M) */
7121f0984d40SFabiano Rosas     bool v8a = ENABLE_ARCH_8 && !arm_dc_feature(s, ARM_FEATURE_M);
7122f0984d40SFabiano Rosas 
7123f0984d40SFabiano Rosas     /* We UNDEF for these UNPREDICTABLE cases.  */
7124f0984d40SFabiano Rosas     if (a->rd == 15 || a->rn == 15 || a->rt == 15
7125f0984d40SFabiano Rosas         || a->rd == a->rn || a->rd == a->rt
7126f0984d40SFabiano Rosas         || (!v8a && s->thumb && (a->rd == 13 || a->rt == 13))
7127f0984d40SFabiano Rosas         || (mop == MO_64
7128f0984d40SFabiano Rosas             && (a->rt2 == 15
7129f0984d40SFabiano Rosas                 || a->rd == a->rt2
7130f0984d40SFabiano Rosas                 || (!v8a && s->thumb && a->rt2 == 13)))) {
7131f0984d40SFabiano Rosas         unallocated_encoding(s);
7132f0984d40SFabiano Rosas         return true;
7133f0984d40SFabiano Rosas     }
7134f0984d40SFabiano Rosas 
7135f0984d40SFabiano Rosas     if (rel) {
7136f0984d40SFabiano Rosas         tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
7137f0984d40SFabiano Rosas     }
7138f0984d40SFabiano Rosas 
7139f0984d40SFabiano Rosas     addr = tcg_temp_local_new_i32();
7140f0984d40SFabiano Rosas     load_reg_var(s, addr, a->rn);
7141f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, a->imm);
7142f0984d40SFabiano Rosas 
7143f0984d40SFabiano Rosas     gen_store_exclusive(s, a->rd, a->rt, a->rt2, addr, mop);
7144f0984d40SFabiano Rosas     tcg_temp_free_i32(addr);
7145f0984d40SFabiano Rosas     return true;
7146f0984d40SFabiano Rosas }
7147f0984d40SFabiano Rosas 
7148f0984d40SFabiano Rosas static bool trans_STREX(DisasContext *s, arg_STREX *a)
7149f0984d40SFabiano Rosas {
7150f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
7151f0984d40SFabiano Rosas         return false;
7152f0984d40SFabiano Rosas     }
7153f0984d40SFabiano Rosas     return op_strex(s, a, MO_32, false);
7154f0984d40SFabiano Rosas }
7155f0984d40SFabiano Rosas 
7156f0984d40SFabiano Rosas static bool trans_STREXD_a32(DisasContext *s, arg_STREX *a)
7157f0984d40SFabiano Rosas {
7158f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6K) {
7159f0984d40SFabiano Rosas         return false;
7160f0984d40SFabiano Rosas     }
7161f0984d40SFabiano Rosas     /* We UNDEF for these UNPREDICTABLE cases.  */
7162f0984d40SFabiano Rosas     if (a->rt & 1) {
7163f0984d40SFabiano Rosas         unallocated_encoding(s);
7164f0984d40SFabiano Rosas         return true;
7165f0984d40SFabiano Rosas     }
7166f0984d40SFabiano Rosas     a->rt2 = a->rt + 1;
7167f0984d40SFabiano Rosas     return op_strex(s, a, MO_64, false);
7168f0984d40SFabiano Rosas }
7169f0984d40SFabiano Rosas 
7170f0984d40SFabiano Rosas static bool trans_STREXD_t32(DisasContext *s, arg_STREX *a)
7171f0984d40SFabiano Rosas {
7172f0984d40SFabiano Rosas     return op_strex(s, a, MO_64, false);
7173f0984d40SFabiano Rosas }
7174f0984d40SFabiano Rosas 
7175f0984d40SFabiano Rosas static bool trans_STREXB(DisasContext *s, arg_STREX *a)
7176f0984d40SFabiano Rosas {
7177f0984d40SFabiano Rosas     if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) {
7178f0984d40SFabiano Rosas         return false;
7179f0984d40SFabiano Rosas     }
7180f0984d40SFabiano Rosas     return op_strex(s, a, MO_8, false);
7181f0984d40SFabiano Rosas }
7182f0984d40SFabiano Rosas 
7183f0984d40SFabiano Rosas static bool trans_STREXH(DisasContext *s, arg_STREX *a)
7184f0984d40SFabiano Rosas {
7185f0984d40SFabiano Rosas     if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) {
7186f0984d40SFabiano Rosas         return false;
7187f0984d40SFabiano Rosas     }
7188f0984d40SFabiano Rosas     return op_strex(s, a, MO_16, false);
7189f0984d40SFabiano Rosas }
7190f0984d40SFabiano Rosas 
7191f0984d40SFabiano Rosas static bool trans_STLEX(DisasContext *s, arg_STREX *a)
7192f0984d40SFabiano Rosas {
7193f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7194f0984d40SFabiano Rosas         return false;
7195f0984d40SFabiano Rosas     }
7196f0984d40SFabiano Rosas     return op_strex(s, a, MO_32, true);
7197f0984d40SFabiano Rosas }
7198f0984d40SFabiano Rosas 
7199f0984d40SFabiano Rosas static bool trans_STLEXD_a32(DisasContext *s, arg_STREX *a)
7200f0984d40SFabiano Rosas {
7201f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7202f0984d40SFabiano Rosas         return false;
7203f0984d40SFabiano Rosas     }
7204f0984d40SFabiano Rosas     /* We UNDEF for these UNPREDICTABLE cases.  */
7205f0984d40SFabiano Rosas     if (a->rt & 1) {
7206f0984d40SFabiano Rosas         unallocated_encoding(s);
7207f0984d40SFabiano Rosas         return true;
7208f0984d40SFabiano Rosas     }
7209f0984d40SFabiano Rosas     a->rt2 = a->rt + 1;
7210f0984d40SFabiano Rosas     return op_strex(s, a, MO_64, true);
7211f0984d40SFabiano Rosas }
7212f0984d40SFabiano Rosas 
7213f0984d40SFabiano Rosas static bool trans_STLEXD_t32(DisasContext *s, arg_STREX *a)
7214f0984d40SFabiano Rosas {
7215f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7216f0984d40SFabiano Rosas         return false;
7217f0984d40SFabiano Rosas     }
7218f0984d40SFabiano Rosas     return op_strex(s, a, MO_64, true);
7219f0984d40SFabiano Rosas }
7220f0984d40SFabiano Rosas 
7221f0984d40SFabiano Rosas static bool trans_STLEXB(DisasContext *s, arg_STREX *a)
7222f0984d40SFabiano Rosas {
7223f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7224f0984d40SFabiano Rosas         return false;
7225f0984d40SFabiano Rosas     }
7226f0984d40SFabiano Rosas     return op_strex(s, a, MO_8, true);
7227f0984d40SFabiano Rosas }
7228f0984d40SFabiano Rosas 
7229f0984d40SFabiano Rosas static bool trans_STLEXH(DisasContext *s, arg_STREX *a)
7230f0984d40SFabiano Rosas {
7231f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7232f0984d40SFabiano Rosas         return false;
7233f0984d40SFabiano Rosas     }
7234f0984d40SFabiano Rosas     return op_strex(s, a, MO_16, true);
7235f0984d40SFabiano Rosas }
7236f0984d40SFabiano Rosas 
7237f0984d40SFabiano Rosas static bool op_stl(DisasContext *s, arg_STL *a, MemOp mop)
7238f0984d40SFabiano Rosas {
7239f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
7240f0984d40SFabiano Rosas 
7241f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7242f0984d40SFabiano Rosas         return false;
7243f0984d40SFabiano Rosas     }
7244f0984d40SFabiano Rosas     /* We UNDEF for these UNPREDICTABLE cases.  */
7245f0984d40SFabiano Rosas     if (a->rn == 15 || a->rt == 15) {
7246f0984d40SFabiano Rosas         unallocated_encoding(s);
7247f0984d40SFabiano Rosas         return true;
7248f0984d40SFabiano Rosas     }
7249f0984d40SFabiano Rosas 
7250f0984d40SFabiano Rosas     addr = load_reg(s, a->rn);
7251f0984d40SFabiano Rosas     tmp = load_reg(s, a->rt);
7252f0984d40SFabiano Rosas     tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
7253f0984d40SFabiano Rosas     gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), mop | MO_ALIGN);
7254f0984d40SFabiano Rosas     disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel | ISSIsWrite);
7255f0984d40SFabiano Rosas 
7256f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
7257f0984d40SFabiano Rosas     tcg_temp_free_i32(addr);
7258f0984d40SFabiano Rosas     return true;
7259f0984d40SFabiano Rosas }
7260f0984d40SFabiano Rosas 
7261f0984d40SFabiano Rosas static bool trans_STL(DisasContext *s, arg_STL *a)
7262f0984d40SFabiano Rosas {
7263f0984d40SFabiano Rosas     return op_stl(s, a, MO_UL);
7264f0984d40SFabiano Rosas }
7265f0984d40SFabiano Rosas 
7266f0984d40SFabiano Rosas static bool trans_STLB(DisasContext *s, arg_STL *a)
7267f0984d40SFabiano Rosas {
7268f0984d40SFabiano Rosas     return op_stl(s, a, MO_UB);
7269f0984d40SFabiano Rosas }
7270f0984d40SFabiano Rosas 
7271f0984d40SFabiano Rosas static bool trans_STLH(DisasContext *s, arg_STL *a)
7272f0984d40SFabiano Rosas {
7273f0984d40SFabiano Rosas     return op_stl(s, a, MO_UW);
7274f0984d40SFabiano Rosas }
7275f0984d40SFabiano Rosas 
7276f0984d40SFabiano Rosas static bool op_ldrex(DisasContext *s, arg_LDREX *a, MemOp mop, bool acq)
7277f0984d40SFabiano Rosas {
7278f0984d40SFabiano Rosas     TCGv_i32 addr;
7279f0984d40SFabiano Rosas     /* Some cases stopped being UNPREDICTABLE in v8A (but not v8M) */
7280f0984d40SFabiano Rosas     bool v8a = ENABLE_ARCH_8 && !arm_dc_feature(s, ARM_FEATURE_M);
7281f0984d40SFabiano Rosas 
7282f0984d40SFabiano Rosas     /* We UNDEF for these UNPREDICTABLE cases.  */
7283f0984d40SFabiano Rosas     if (a->rn == 15 || a->rt == 15
7284f0984d40SFabiano Rosas         || (!v8a && s->thumb && a->rt == 13)
7285f0984d40SFabiano Rosas         || (mop == MO_64
7286f0984d40SFabiano Rosas             && (a->rt2 == 15 || a->rt == a->rt2
7287f0984d40SFabiano Rosas                 || (!v8a && s->thumb && a->rt2 == 13)))) {
7288f0984d40SFabiano Rosas         unallocated_encoding(s);
7289f0984d40SFabiano Rosas         return true;
7290f0984d40SFabiano Rosas     }
7291f0984d40SFabiano Rosas 
7292f0984d40SFabiano Rosas     addr = tcg_temp_local_new_i32();
7293f0984d40SFabiano Rosas     load_reg_var(s, addr, a->rn);
7294f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, a->imm);
7295f0984d40SFabiano Rosas 
7296f0984d40SFabiano Rosas     gen_load_exclusive(s, a->rt, a->rt2, addr, mop);
7297f0984d40SFabiano Rosas     tcg_temp_free_i32(addr);
7298f0984d40SFabiano Rosas 
7299f0984d40SFabiano Rosas     if (acq) {
7300f0984d40SFabiano Rosas         tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
7301f0984d40SFabiano Rosas     }
7302f0984d40SFabiano Rosas     return true;
7303f0984d40SFabiano Rosas }
7304f0984d40SFabiano Rosas 
7305f0984d40SFabiano Rosas static bool trans_LDREX(DisasContext *s, arg_LDREX *a)
7306f0984d40SFabiano Rosas {
7307f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
7308f0984d40SFabiano Rosas         return false;
7309f0984d40SFabiano Rosas     }
7310f0984d40SFabiano Rosas     return op_ldrex(s, a, MO_32, false);
7311f0984d40SFabiano Rosas }
7312f0984d40SFabiano Rosas 
7313f0984d40SFabiano Rosas static bool trans_LDREXD_a32(DisasContext *s, arg_LDREX *a)
7314f0984d40SFabiano Rosas {
7315f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6K) {
7316f0984d40SFabiano Rosas         return false;
7317f0984d40SFabiano Rosas     }
7318f0984d40SFabiano Rosas     /* We UNDEF for these UNPREDICTABLE cases.  */
7319f0984d40SFabiano Rosas     if (a->rt & 1) {
7320f0984d40SFabiano Rosas         unallocated_encoding(s);
7321f0984d40SFabiano Rosas         return true;
7322f0984d40SFabiano Rosas     }
7323f0984d40SFabiano Rosas     a->rt2 = a->rt + 1;
7324f0984d40SFabiano Rosas     return op_ldrex(s, a, MO_64, false);
7325f0984d40SFabiano Rosas }
7326f0984d40SFabiano Rosas 
7327f0984d40SFabiano Rosas static bool trans_LDREXD_t32(DisasContext *s, arg_LDREX *a)
7328f0984d40SFabiano Rosas {
7329f0984d40SFabiano Rosas     return op_ldrex(s, a, MO_64, false);
7330f0984d40SFabiano Rosas }
7331f0984d40SFabiano Rosas 
7332f0984d40SFabiano Rosas static bool trans_LDREXB(DisasContext *s, arg_LDREX *a)
7333f0984d40SFabiano Rosas {
7334f0984d40SFabiano Rosas     if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) {
7335f0984d40SFabiano Rosas         return false;
7336f0984d40SFabiano Rosas     }
7337f0984d40SFabiano Rosas     return op_ldrex(s, a, MO_8, false);
7338f0984d40SFabiano Rosas }
7339f0984d40SFabiano Rosas 
7340f0984d40SFabiano Rosas static bool trans_LDREXH(DisasContext *s, arg_LDREX *a)
7341f0984d40SFabiano Rosas {
7342f0984d40SFabiano Rosas     if (s->thumb ? !ENABLE_ARCH_7 : !ENABLE_ARCH_6K) {
7343f0984d40SFabiano Rosas         return false;
7344f0984d40SFabiano Rosas     }
7345f0984d40SFabiano Rosas     return op_ldrex(s, a, MO_16, false);
7346f0984d40SFabiano Rosas }
7347f0984d40SFabiano Rosas 
7348f0984d40SFabiano Rosas static bool trans_LDAEX(DisasContext *s, arg_LDREX *a)
7349f0984d40SFabiano Rosas {
7350f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7351f0984d40SFabiano Rosas         return false;
7352f0984d40SFabiano Rosas     }
7353f0984d40SFabiano Rosas     return op_ldrex(s, a, MO_32, true);
7354f0984d40SFabiano Rosas }
7355f0984d40SFabiano Rosas 
7356f0984d40SFabiano Rosas static bool trans_LDAEXD_a32(DisasContext *s, arg_LDREX *a)
7357f0984d40SFabiano Rosas {
7358f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7359f0984d40SFabiano Rosas         return false;
7360f0984d40SFabiano Rosas     }
7361f0984d40SFabiano Rosas     /* We UNDEF for these UNPREDICTABLE cases.  */
7362f0984d40SFabiano Rosas     if (a->rt & 1) {
7363f0984d40SFabiano Rosas         unallocated_encoding(s);
7364f0984d40SFabiano Rosas         return true;
7365f0984d40SFabiano Rosas     }
7366f0984d40SFabiano Rosas     a->rt2 = a->rt + 1;
7367f0984d40SFabiano Rosas     return op_ldrex(s, a, MO_64, true);
7368f0984d40SFabiano Rosas }
7369f0984d40SFabiano Rosas 
7370f0984d40SFabiano Rosas static bool trans_LDAEXD_t32(DisasContext *s, arg_LDREX *a)
7371f0984d40SFabiano Rosas {
7372f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7373f0984d40SFabiano Rosas         return false;
7374f0984d40SFabiano Rosas     }
7375f0984d40SFabiano Rosas     return op_ldrex(s, a, MO_64, true);
7376f0984d40SFabiano Rosas }
7377f0984d40SFabiano Rosas 
7378f0984d40SFabiano Rosas static bool trans_LDAEXB(DisasContext *s, arg_LDREX *a)
7379f0984d40SFabiano Rosas {
7380f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7381f0984d40SFabiano Rosas         return false;
7382f0984d40SFabiano Rosas     }
7383f0984d40SFabiano Rosas     return op_ldrex(s, a, MO_8, true);
7384f0984d40SFabiano Rosas }
7385f0984d40SFabiano Rosas 
7386f0984d40SFabiano Rosas static bool trans_LDAEXH(DisasContext *s, arg_LDREX *a)
7387f0984d40SFabiano Rosas {
7388f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7389f0984d40SFabiano Rosas         return false;
7390f0984d40SFabiano Rosas     }
7391f0984d40SFabiano Rosas     return op_ldrex(s, a, MO_16, true);
7392f0984d40SFabiano Rosas }
7393f0984d40SFabiano Rosas 
7394f0984d40SFabiano Rosas static bool op_lda(DisasContext *s, arg_LDA *a, MemOp mop)
7395f0984d40SFabiano Rosas {
7396f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
7397f0984d40SFabiano Rosas 
7398f0984d40SFabiano Rosas     if (!ENABLE_ARCH_8) {
7399f0984d40SFabiano Rosas         return false;
7400f0984d40SFabiano Rosas     }
7401f0984d40SFabiano Rosas     /* We UNDEF for these UNPREDICTABLE cases.  */
7402f0984d40SFabiano Rosas     if (a->rn == 15 || a->rt == 15) {
7403f0984d40SFabiano Rosas         unallocated_encoding(s);
7404f0984d40SFabiano Rosas         return true;
7405f0984d40SFabiano Rosas     }
7406f0984d40SFabiano Rosas 
7407f0984d40SFabiano Rosas     addr = load_reg(s, a->rn);
7408f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
7409f0984d40SFabiano Rosas     gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop | MO_ALIGN);
7410f0984d40SFabiano Rosas     disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel);
7411f0984d40SFabiano Rosas     tcg_temp_free_i32(addr);
7412f0984d40SFabiano Rosas 
7413f0984d40SFabiano Rosas     store_reg(s, a->rt, tmp);
7414f0984d40SFabiano Rosas     tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
7415f0984d40SFabiano Rosas     return true;
7416f0984d40SFabiano Rosas }
7417f0984d40SFabiano Rosas 
7418f0984d40SFabiano Rosas static bool trans_LDA(DisasContext *s, arg_LDA *a)
7419f0984d40SFabiano Rosas {
7420f0984d40SFabiano Rosas     return op_lda(s, a, MO_UL);
7421f0984d40SFabiano Rosas }
7422f0984d40SFabiano Rosas 
7423f0984d40SFabiano Rosas static bool trans_LDAB(DisasContext *s, arg_LDA *a)
7424f0984d40SFabiano Rosas {
7425f0984d40SFabiano Rosas     return op_lda(s, a, MO_UB);
7426f0984d40SFabiano Rosas }
7427f0984d40SFabiano Rosas 
7428f0984d40SFabiano Rosas static bool trans_LDAH(DisasContext *s, arg_LDA *a)
7429f0984d40SFabiano Rosas {
7430f0984d40SFabiano Rosas     return op_lda(s, a, MO_UW);
7431f0984d40SFabiano Rosas }
7432f0984d40SFabiano Rosas 
7433f0984d40SFabiano Rosas /*
7434f0984d40SFabiano Rosas  * Media instructions
7435f0984d40SFabiano Rosas  */
7436f0984d40SFabiano Rosas 
7437f0984d40SFabiano Rosas static bool trans_USADA8(DisasContext *s, arg_USADA8 *a)
7438f0984d40SFabiano Rosas {
7439f0984d40SFabiano Rosas     TCGv_i32 t1, t2;
7440f0984d40SFabiano Rosas 
7441f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
7442f0984d40SFabiano Rosas         return false;
7443f0984d40SFabiano Rosas     }
7444f0984d40SFabiano Rosas 
7445f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
7446f0984d40SFabiano Rosas     t2 = load_reg(s, a->rm);
7447f0984d40SFabiano Rosas     gen_helper_usad8(t1, t1, t2);
7448f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
7449f0984d40SFabiano Rosas     if (a->ra != 15) {
7450f0984d40SFabiano Rosas         t2 = load_reg(s, a->ra);
7451f0984d40SFabiano Rosas         tcg_gen_add_i32(t1, t1, t2);
7452f0984d40SFabiano Rosas         tcg_temp_free_i32(t2);
7453f0984d40SFabiano Rosas     }
7454f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
7455f0984d40SFabiano Rosas     return true;
7456f0984d40SFabiano Rosas }
7457f0984d40SFabiano Rosas 
7458f0984d40SFabiano Rosas static bool op_bfx(DisasContext *s, arg_UBFX *a, bool u)
7459f0984d40SFabiano Rosas {
7460f0984d40SFabiano Rosas     TCGv_i32 tmp;
7461f0984d40SFabiano Rosas     int width = a->widthm1 + 1;
7462f0984d40SFabiano Rosas     int shift = a->lsb;
7463f0984d40SFabiano Rosas 
7464f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6T2) {
7465f0984d40SFabiano Rosas         return false;
7466f0984d40SFabiano Rosas     }
7467f0984d40SFabiano Rosas     if (shift + width > 32) {
7468f0984d40SFabiano Rosas         /* UNPREDICTABLE; we choose to UNDEF */
7469f0984d40SFabiano Rosas         unallocated_encoding(s);
7470f0984d40SFabiano Rosas         return true;
7471f0984d40SFabiano Rosas     }
7472f0984d40SFabiano Rosas 
7473f0984d40SFabiano Rosas     tmp = load_reg(s, a->rn);
7474f0984d40SFabiano Rosas     if (u) {
7475f0984d40SFabiano Rosas         tcg_gen_extract_i32(tmp, tmp, shift, width);
7476f0984d40SFabiano Rosas     } else {
7477f0984d40SFabiano Rosas         tcg_gen_sextract_i32(tmp, tmp, shift, width);
7478f0984d40SFabiano Rosas     }
7479f0984d40SFabiano Rosas     store_reg(s, a->rd, tmp);
7480f0984d40SFabiano Rosas     return true;
7481f0984d40SFabiano Rosas }
7482f0984d40SFabiano Rosas 
7483f0984d40SFabiano Rosas static bool trans_SBFX(DisasContext *s, arg_SBFX *a)
7484f0984d40SFabiano Rosas {
7485f0984d40SFabiano Rosas     return op_bfx(s, a, false);
7486f0984d40SFabiano Rosas }
7487f0984d40SFabiano Rosas 
7488f0984d40SFabiano Rosas static bool trans_UBFX(DisasContext *s, arg_UBFX *a)
7489f0984d40SFabiano Rosas {
7490f0984d40SFabiano Rosas     return op_bfx(s, a, true);
7491f0984d40SFabiano Rosas }
7492f0984d40SFabiano Rosas 
7493f0984d40SFabiano Rosas static bool trans_BFCI(DisasContext *s, arg_BFCI *a)
7494f0984d40SFabiano Rosas {
7495f0984d40SFabiano Rosas     TCGv_i32 tmp;
7496f0984d40SFabiano Rosas     int msb = a->msb, lsb = a->lsb;
7497f0984d40SFabiano Rosas     int width;
7498f0984d40SFabiano Rosas 
7499f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6T2) {
7500f0984d40SFabiano Rosas         return false;
7501f0984d40SFabiano Rosas     }
7502f0984d40SFabiano Rosas     if (msb < lsb) {
7503f0984d40SFabiano Rosas         /* UNPREDICTABLE; we choose to UNDEF */
7504f0984d40SFabiano Rosas         unallocated_encoding(s);
7505f0984d40SFabiano Rosas         return true;
7506f0984d40SFabiano Rosas     }
7507f0984d40SFabiano Rosas 
7508f0984d40SFabiano Rosas     width = msb + 1 - lsb;
7509f0984d40SFabiano Rosas     if (a->rn == 15) {
7510f0984d40SFabiano Rosas         /* BFC */
7511f0984d40SFabiano Rosas         tmp = tcg_const_i32(0);
7512f0984d40SFabiano Rosas     } else {
7513f0984d40SFabiano Rosas         /* BFI */
7514f0984d40SFabiano Rosas         tmp = load_reg(s, a->rn);
7515f0984d40SFabiano Rosas     }
7516f0984d40SFabiano Rosas     if (width != 32) {
7517f0984d40SFabiano Rosas         TCGv_i32 tmp2 = load_reg(s, a->rd);
7518f0984d40SFabiano Rosas         tcg_gen_deposit_i32(tmp, tmp2, tmp, lsb, width);
7519f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp2);
7520f0984d40SFabiano Rosas     }
7521f0984d40SFabiano Rosas     store_reg(s, a->rd, tmp);
7522f0984d40SFabiano Rosas     return true;
7523f0984d40SFabiano Rosas }
7524f0984d40SFabiano Rosas 
7525f0984d40SFabiano Rosas static bool trans_UDF(DisasContext *s, arg_UDF *a)
7526f0984d40SFabiano Rosas {
7527f0984d40SFabiano Rosas     unallocated_encoding(s);
7528f0984d40SFabiano Rosas     return true;
7529f0984d40SFabiano Rosas }
7530f0984d40SFabiano Rosas 
7531f0984d40SFabiano Rosas /*
7532f0984d40SFabiano Rosas  * Parallel addition and subtraction
7533f0984d40SFabiano Rosas  */
7534f0984d40SFabiano Rosas 
7535f0984d40SFabiano Rosas static bool op_par_addsub(DisasContext *s, arg_rrr *a,
7536f0984d40SFabiano Rosas                           void (*gen)(TCGv_i32, TCGv_i32, TCGv_i32))
7537f0984d40SFabiano Rosas {
7538f0984d40SFabiano Rosas     TCGv_i32 t0, t1;
7539f0984d40SFabiano Rosas 
7540f0984d40SFabiano Rosas     if (s->thumb
7541f0984d40SFabiano Rosas         ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
7542f0984d40SFabiano Rosas         : !ENABLE_ARCH_6) {
7543f0984d40SFabiano Rosas         return false;
7544f0984d40SFabiano Rosas     }
7545f0984d40SFabiano Rosas 
7546f0984d40SFabiano Rosas     t0 = load_reg(s, a->rn);
7547f0984d40SFabiano Rosas     t1 = load_reg(s, a->rm);
7548f0984d40SFabiano Rosas 
7549f0984d40SFabiano Rosas     gen(t0, t0, t1);
7550f0984d40SFabiano Rosas 
7551f0984d40SFabiano Rosas     tcg_temp_free_i32(t1);
7552f0984d40SFabiano Rosas     store_reg(s, a->rd, t0);
7553f0984d40SFabiano Rosas     return true;
7554f0984d40SFabiano Rosas }
7555f0984d40SFabiano Rosas 
7556f0984d40SFabiano Rosas static bool op_par_addsub_ge(DisasContext *s, arg_rrr *a,
7557f0984d40SFabiano Rosas                              void (*gen)(TCGv_i32, TCGv_i32,
7558f0984d40SFabiano Rosas                                          TCGv_i32, TCGv_ptr))
7559f0984d40SFabiano Rosas {
7560f0984d40SFabiano Rosas     TCGv_i32 t0, t1;
7561f0984d40SFabiano Rosas     TCGv_ptr ge;
7562f0984d40SFabiano Rosas 
7563f0984d40SFabiano Rosas     if (s->thumb
7564f0984d40SFabiano Rosas         ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
7565f0984d40SFabiano Rosas         : !ENABLE_ARCH_6) {
7566f0984d40SFabiano Rosas         return false;
7567f0984d40SFabiano Rosas     }
7568f0984d40SFabiano Rosas 
7569f0984d40SFabiano Rosas     t0 = load_reg(s, a->rn);
7570f0984d40SFabiano Rosas     t1 = load_reg(s, a->rm);
7571f0984d40SFabiano Rosas 
7572f0984d40SFabiano Rosas     ge = tcg_temp_new_ptr();
7573f0984d40SFabiano Rosas     tcg_gen_addi_ptr(ge, cpu_env, offsetof(CPUARMState, GE));
7574f0984d40SFabiano Rosas     gen(t0, t0, t1, ge);
7575f0984d40SFabiano Rosas 
7576f0984d40SFabiano Rosas     tcg_temp_free_ptr(ge);
7577f0984d40SFabiano Rosas     tcg_temp_free_i32(t1);
7578f0984d40SFabiano Rosas     store_reg(s, a->rd, t0);
7579f0984d40SFabiano Rosas     return true;
7580f0984d40SFabiano Rosas }
7581f0984d40SFabiano Rosas 
7582f0984d40SFabiano Rosas #define DO_PAR_ADDSUB(NAME, helper) \
7583f0984d40SFabiano Rosas static bool trans_##NAME(DisasContext *s, arg_rrr *a)   \
7584f0984d40SFabiano Rosas {                                                       \
7585f0984d40SFabiano Rosas     return op_par_addsub(s, a, helper);                 \
7586f0984d40SFabiano Rosas }
7587f0984d40SFabiano Rosas 
7588f0984d40SFabiano Rosas #define DO_PAR_ADDSUB_GE(NAME, helper) \
7589f0984d40SFabiano Rosas static bool trans_##NAME(DisasContext *s, arg_rrr *a)   \
7590f0984d40SFabiano Rosas {                                                       \
7591f0984d40SFabiano Rosas     return op_par_addsub_ge(s, a, helper);              \
7592f0984d40SFabiano Rosas }
7593f0984d40SFabiano Rosas 
7594f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(SADD16, gen_helper_sadd16)
7595f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(SASX, gen_helper_saddsubx)
7596f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(SSAX, gen_helper_ssubaddx)
7597f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(SSUB16, gen_helper_ssub16)
7598f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(SADD8, gen_helper_sadd8)
7599f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(SSUB8, gen_helper_ssub8)
7600f0984d40SFabiano Rosas 
7601f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(UADD16, gen_helper_uadd16)
7602f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(UASX, gen_helper_uaddsubx)
7603f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(USAX, gen_helper_usubaddx)
7604f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(USUB16, gen_helper_usub16)
7605f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(UADD8, gen_helper_uadd8)
7606f0984d40SFabiano Rosas DO_PAR_ADDSUB_GE(USUB8, gen_helper_usub8)
7607f0984d40SFabiano Rosas 
7608f0984d40SFabiano Rosas DO_PAR_ADDSUB(QADD16, gen_helper_qadd16)
7609f0984d40SFabiano Rosas DO_PAR_ADDSUB(QASX, gen_helper_qaddsubx)
7610f0984d40SFabiano Rosas DO_PAR_ADDSUB(QSAX, gen_helper_qsubaddx)
7611f0984d40SFabiano Rosas DO_PAR_ADDSUB(QSUB16, gen_helper_qsub16)
7612f0984d40SFabiano Rosas DO_PAR_ADDSUB(QADD8, gen_helper_qadd8)
7613f0984d40SFabiano Rosas DO_PAR_ADDSUB(QSUB8, gen_helper_qsub8)
7614f0984d40SFabiano Rosas 
7615f0984d40SFabiano Rosas DO_PAR_ADDSUB(UQADD16, gen_helper_uqadd16)
7616f0984d40SFabiano Rosas DO_PAR_ADDSUB(UQASX, gen_helper_uqaddsubx)
7617f0984d40SFabiano Rosas DO_PAR_ADDSUB(UQSAX, gen_helper_uqsubaddx)
7618f0984d40SFabiano Rosas DO_PAR_ADDSUB(UQSUB16, gen_helper_uqsub16)
7619f0984d40SFabiano Rosas DO_PAR_ADDSUB(UQADD8, gen_helper_uqadd8)
7620f0984d40SFabiano Rosas DO_PAR_ADDSUB(UQSUB8, gen_helper_uqsub8)
7621f0984d40SFabiano Rosas 
7622f0984d40SFabiano Rosas DO_PAR_ADDSUB(SHADD16, gen_helper_shadd16)
7623f0984d40SFabiano Rosas DO_PAR_ADDSUB(SHASX, gen_helper_shaddsubx)
7624f0984d40SFabiano Rosas DO_PAR_ADDSUB(SHSAX, gen_helper_shsubaddx)
7625f0984d40SFabiano Rosas DO_PAR_ADDSUB(SHSUB16, gen_helper_shsub16)
7626f0984d40SFabiano Rosas DO_PAR_ADDSUB(SHADD8, gen_helper_shadd8)
7627f0984d40SFabiano Rosas DO_PAR_ADDSUB(SHSUB8, gen_helper_shsub8)
7628f0984d40SFabiano Rosas 
7629f0984d40SFabiano Rosas DO_PAR_ADDSUB(UHADD16, gen_helper_uhadd16)
7630f0984d40SFabiano Rosas DO_PAR_ADDSUB(UHASX, gen_helper_uhaddsubx)
7631f0984d40SFabiano Rosas DO_PAR_ADDSUB(UHSAX, gen_helper_uhsubaddx)
7632f0984d40SFabiano Rosas DO_PAR_ADDSUB(UHSUB16, gen_helper_uhsub16)
7633f0984d40SFabiano Rosas DO_PAR_ADDSUB(UHADD8, gen_helper_uhadd8)
7634f0984d40SFabiano Rosas DO_PAR_ADDSUB(UHSUB8, gen_helper_uhsub8)
7635f0984d40SFabiano Rosas 
7636f0984d40SFabiano Rosas #undef DO_PAR_ADDSUB
7637f0984d40SFabiano Rosas #undef DO_PAR_ADDSUB_GE
7638f0984d40SFabiano Rosas 
7639f0984d40SFabiano Rosas /*
7640f0984d40SFabiano Rosas  * Packing, unpacking, saturation, and reversal
7641f0984d40SFabiano Rosas  */
7642f0984d40SFabiano Rosas 
7643f0984d40SFabiano Rosas static bool trans_PKH(DisasContext *s, arg_PKH *a)
7644f0984d40SFabiano Rosas {
7645f0984d40SFabiano Rosas     TCGv_i32 tn, tm;
7646f0984d40SFabiano Rosas     int shift = a->imm;
7647f0984d40SFabiano Rosas 
7648f0984d40SFabiano Rosas     if (s->thumb
7649f0984d40SFabiano Rosas         ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
7650f0984d40SFabiano Rosas         : !ENABLE_ARCH_6) {
7651f0984d40SFabiano Rosas         return false;
7652f0984d40SFabiano Rosas     }
7653f0984d40SFabiano Rosas 
7654f0984d40SFabiano Rosas     tn = load_reg(s, a->rn);
7655f0984d40SFabiano Rosas     tm = load_reg(s, a->rm);
7656f0984d40SFabiano Rosas     if (a->tb) {
7657f0984d40SFabiano Rosas         /* PKHTB */
7658f0984d40SFabiano Rosas         if (shift == 0) {
7659f0984d40SFabiano Rosas             shift = 31;
7660f0984d40SFabiano Rosas         }
7661f0984d40SFabiano Rosas         tcg_gen_sari_i32(tm, tm, shift);
7662f0984d40SFabiano Rosas         tcg_gen_deposit_i32(tn, tn, tm, 0, 16);
7663f0984d40SFabiano Rosas     } else {
7664f0984d40SFabiano Rosas         /* PKHBT */
7665f0984d40SFabiano Rosas         tcg_gen_shli_i32(tm, tm, shift);
7666f0984d40SFabiano Rosas         tcg_gen_deposit_i32(tn, tm, tn, 0, 16);
7667f0984d40SFabiano Rosas     }
7668f0984d40SFabiano Rosas     tcg_temp_free_i32(tm);
7669f0984d40SFabiano Rosas     store_reg(s, a->rd, tn);
7670f0984d40SFabiano Rosas     return true;
7671f0984d40SFabiano Rosas }
7672f0984d40SFabiano Rosas 
7673f0984d40SFabiano Rosas static bool op_sat(DisasContext *s, arg_sat *a,
7674f0984d40SFabiano Rosas                    void (*gen)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
7675f0984d40SFabiano Rosas {
7676f0984d40SFabiano Rosas     TCGv_i32 tmp;
7677f0984d40SFabiano Rosas     int shift = a->imm;
7678f0984d40SFabiano Rosas 
7679f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
7680f0984d40SFabiano Rosas         return false;
7681f0984d40SFabiano Rosas     }
7682f0984d40SFabiano Rosas 
7683f0984d40SFabiano Rosas     tmp = load_reg(s, a->rn);
7684f0984d40SFabiano Rosas     if (a->sh) {
7685f0984d40SFabiano Rosas         tcg_gen_sari_i32(tmp, tmp, shift ? shift : 31);
7686f0984d40SFabiano Rosas     } else {
7687f0984d40SFabiano Rosas         tcg_gen_shli_i32(tmp, tmp, shift);
7688f0984d40SFabiano Rosas     }
7689f0984d40SFabiano Rosas 
7690f0984d40SFabiano Rosas     gen(tmp, cpu_env, tmp, tcg_constant_i32(a->satimm));
7691f0984d40SFabiano Rosas 
7692f0984d40SFabiano Rosas     store_reg(s, a->rd, tmp);
7693f0984d40SFabiano Rosas     return true;
7694f0984d40SFabiano Rosas }
7695f0984d40SFabiano Rosas 
7696f0984d40SFabiano Rosas static bool trans_SSAT(DisasContext *s, arg_sat *a)
7697f0984d40SFabiano Rosas {
7698f0984d40SFabiano Rosas     return op_sat(s, a, gen_helper_ssat);
7699f0984d40SFabiano Rosas }
7700f0984d40SFabiano Rosas 
7701f0984d40SFabiano Rosas static bool trans_USAT(DisasContext *s, arg_sat *a)
7702f0984d40SFabiano Rosas {
7703f0984d40SFabiano Rosas     return op_sat(s, a, gen_helper_usat);
7704f0984d40SFabiano Rosas }
7705f0984d40SFabiano Rosas 
7706f0984d40SFabiano Rosas static bool trans_SSAT16(DisasContext *s, arg_sat *a)
7707f0984d40SFabiano Rosas {
7708f0984d40SFabiano Rosas     if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
7709f0984d40SFabiano Rosas         return false;
7710f0984d40SFabiano Rosas     }
7711f0984d40SFabiano Rosas     return op_sat(s, a, gen_helper_ssat16);
7712f0984d40SFabiano Rosas }
7713f0984d40SFabiano Rosas 
7714f0984d40SFabiano Rosas static bool trans_USAT16(DisasContext *s, arg_sat *a)
7715f0984d40SFabiano Rosas {
7716f0984d40SFabiano Rosas     if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
7717f0984d40SFabiano Rosas         return false;
7718f0984d40SFabiano Rosas     }
7719f0984d40SFabiano Rosas     return op_sat(s, a, gen_helper_usat16);
7720f0984d40SFabiano Rosas }
7721f0984d40SFabiano Rosas 
7722f0984d40SFabiano Rosas static bool op_xta(DisasContext *s, arg_rrr_rot *a,
7723f0984d40SFabiano Rosas                    void (*gen_extract)(TCGv_i32, TCGv_i32),
7724f0984d40SFabiano Rosas                    void (*gen_add)(TCGv_i32, TCGv_i32, TCGv_i32))
7725f0984d40SFabiano Rosas {
7726f0984d40SFabiano Rosas     TCGv_i32 tmp;
7727f0984d40SFabiano Rosas 
7728f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
7729f0984d40SFabiano Rosas         return false;
7730f0984d40SFabiano Rosas     }
7731f0984d40SFabiano Rosas 
7732f0984d40SFabiano Rosas     tmp = load_reg(s, a->rm);
7733f0984d40SFabiano Rosas     /*
7734f0984d40SFabiano Rosas      * TODO: In many cases we could do a shift instead of a rotate.
7735f0984d40SFabiano Rosas      * Combined with a simple extend, that becomes an extract.
7736f0984d40SFabiano Rosas      */
7737f0984d40SFabiano Rosas     tcg_gen_rotri_i32(tmp, tmp, a->rot * 8);
7738f0984d40SFabiano Rosas     gen_extract(tmp, tmp);
7739f0984d40SFabiano Rosas 
7740f0984d40SFabiano Rosas     if (a->rn != 15) {
7741f0984d40SFabiano Rosas         TCGv_i32 tmp2 = load_reg(s, a->rn);
7742f0984d40SFabiano Rosas         gen_add(tmp, tmp, tmp2);
7743f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp2);
7744f0984d40SFabiano Rosas     }
7745f0984d40SFabiano Rosas     store_reg(s, a->rd, tmp);
7746f0984d40SFabiano Rosas     return true;
7747f0984d40SFabiano Rosas }
7748f0984d40SFabiano Rosas 
7749f0984d40SFabiano Rosas static bool trans_SXTAB(DisasContext *s, arg_rrr_rot *a)
7750f0984d40SFabiano Rosas {
7751f0984d40SFabiano Rosas     return op_xta(s, a, tcg_gen_ext8s_i32, tcg_gen_add_i32);
7752f0984d40SFabiano Rosas }
7753f0984d40SFabiano Rosas 
7754f0984d40SFabiano Rosas static bool trans_SXTAH(DisasContext *s, arg_rrr_rot *a)
7755f0984d40SFabiano Rosas {
7756f0984d40SFabiano Rosas     return op_xta(s, a, tcg_gen_ext16s_i32, tcg_gen_add_i32);
7757f0984d40SFabiano Rosas }
7758f0984d40SFabiano Rosas 
7759f0984d40SFabiano Rosas static bool trans_SXTAB16(DisasContext *s, arg_rrr_rot *a)
7760f0984d40SFabiano Rosas {
7761f0984d40SFabiano Rosas     if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
7762f0984d40SFabiano Rosas         return false;
7763f0984d40SFabiano Rosas     }
7764f0984d40SFabiano Rosas     return op_xta(s, a, gen_helper_sxtb16, gen_add16);
7765f0984d40SFabiano Rosas }
7766f0984d40SFabiano Rosas 
7767f0984d40SFabiano Rosas static bool trans_UXTAB(DisasContext *s, arg_rrr_rot *a)
7768f0984d40SFabiano Rosas {
7769f0984d40SFabiano Rosas     return op_xta(s, a, tcg_gen_ext8u_i32, tcg_gen_add_i32);
7770f0984d40SFabiano Rosas }
7771f0984d40SFabiano Rosas 
7772f0984d40SFabiano Rosas static bool trans_UXTAH(DisasContext *s, arg_rrr_rot *a)
7773f0984d40SFabiano Rosas {
7774f0984d40SFabiano Rosas     return op_xta(s, a, tcg_gen_ext16u_i32, tcg_gen_add_i32);
7775f0984d40SFabiano Rosas }
7776f0984d40SFabiano Rosas 
7777f0984d40SFabiano Rosas static bool trans_UXTAB16(DisasContext *s, arg_rrr_rot *a)
7778f0984d40SFabiano Rosas {
7779f0984d40SFabiano Rosas     if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
7780f0984d40SFabiano Rosas         return false;
7781f0984d40SFabiano Rosas     }
7782f0984d40SFabiano Rosas     return op_xta(s, a, gen_helper_uxtb16, gen_add16);
7783f0984d40SFabiano Rosas }
7784f0984d40SFabiano Rosas 
7785f0984d40SFabiano Rosas static bool trans_SEL(DisasContext *s, arg_rrr *a)
7786f0984d40SFabiano Rosas {
7787f0984d40SFabiano Rosas     TCGv_i32 t1, t2, t3;
7788f0984d40SFabiano Rosas 
7789f0984d40SFabiano Rosas     if (s->thumb
7790f0984d40SFabiano Rosas         ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
7791f0984d40SFabiano Rosas         : !ENABLE_ARCH_6) {
7792f0984d40SFabiano Rosas         return false;
7793f0984d40SFabiano Rosas     }
7794f0984d40SFabiano Rosas 
7795f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
7796f0984d40SFabiano Rosas     t2 = load_reg(s, a->rm);
7797f0984d40SFabiano Rosas     t3 = tcg_temp_new_i32();
7798f0984d40SFabiano Rosas     tcg_gen_ld_i32(t3, cpu_env, offsetof(CPUARMState, GE));
7799f0984d40SFabiano Rosas     gen_helper_sel_flags(t1, t3, t1, t2);
7800f0984d40SFabiano Rosas     tcg_temp_free_i32(t3);
7801f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
7802f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
7803f0984d40SFabiano Rosas     return true;
7804f0984d40SFabiano Rosas }
7805f0984d40SFabiano Rosas 
7806f0984d40SFabiano Rosas static bool op_rr(DisasContext *s, arg_rr *a,
7807f0984d40SFabiano Rosas                   void (*gen)(TCGv_i32, TCGv_i32))
7808f0984d40SFabiano Rosas {
7809f0984d40SFabiano Rosas     TCGv_i32 tmp;
7810f0984d40SFabiano Rosas 
7811f0984d40SFabiano Rosas     tmp = load_reg(s, a->rm);
7812f0984d40SFabiano Rosas     gen(tmp, tmp);
7813f0984d40SFabiano Rosas     store_reg(s, a->rd, tmp);
7814f0984d40SFabiano Rosas     return true;
7815f0984d40SFabiano Rosas }
7816f0984d40SFabiano Rosas 
7817f0984d40SFabiano Rosas static bool trans_REV(DisasContext *s, arg_rr *a)
7818f0984d40SFabiano Rosas {
7819f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
7820f0984d40SFabiano Rosas         return false;
7821f0984d40SFabiano Rosas     }
7822f0984d40SFabiano Rosas     return op_rr(s, a, tcg_gen_bswap32_i32);
7823f0984d40SFabiano Rosas }
7824f0984d40SFabiano Rosas 
7825f0984d40SFabiano Rosas static bool trans_REV16(DisasContext *s, arg_rr *a)
7826f0984d40SFabiano Rosas {
7827f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
7828f0984d40SFabiano Rosas         return false;
7829f0984d40SFabiano Rosas     }
7830f0984d40SFabiano Rosas     return op_rr(s, a, gen_rev16);
7831f0984d40SFabiano Rosas }
7832f0984d40SFabiano Rosas 
7833f0984d40SFabiano Rosas static bool trans_REVSH(DisasContext *s, arg_rr *a)
7834f0984d40SFabiano Rosas {
7835f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
7836f0984d40SFabiano Rosas         return false;
7837f0984d40SFabiano Rosas     }
7838f0984d40SFabiano Rosas     return op_rr(s, a, gen_revsh);
7839f0984d40SFabiano Rosas }
7840f0984d40SFabiano Rosas 
7841f0984d40SFabiano Rosas static bool trans_RBIT(DisasContext *s, arg_rr *a)
7842f0984d40SFabiano Rosas {
7843f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6T2) {
7844f0984d40SFabiano Rosas         return false;
7845f0984d40SFabiano Rosas     }
7846f0984d40SFabiano Rosas     return op_rr(s, a, gen_helper_rbit);
7847f0984d40SFabiano Rosas }
7848f0984d40SFabiano Rosas 
7849f0984d40SFabiano Rosas /*
7850f0984d40SFabiano Rosas  * Signed multiply, signed and unsigned divide
7851f0984d40SFabiano Rosas  */
7852f0984d40SFabiano Rosas 
7853f0984d40SFabiano Rosas static bool op_smlad(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub)
7854f0984d40SFabiano Rosas {
7855f0984d40SFabiano Rosas     TCGv_i32 t1, t2;
7856f0984d40SFabiano Rosas 
7857f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
7858f0984d40SFabiano Rosas         return false;
7859f0984d40SFabiano Rosas     }
7860f0984d40SFabiano Rosas 
7861f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
7862f0984d40SFabiano Rosas     t2 = load_reg(s, a->rm);
7863f0984d40SFabiano Rosas     if (m_swap) {
7864f0984d40SFabiano Rosas         gen_swap_half(t2, t2);
7865f0984d40SFabiano Rosas     }
7866f0984d40SFabiano Rosas     gen_smul_dual(t1, t2);
7867f0984d40SFabiano Rosas 
7868f0984d40SFabiano Rosas     if (sub) {
7869f0984d40SFabiano Rosas         /*
7870f0984d40SFabiano Rosas          * This subtraction cannot overflow, so we can do a simple
7871f0984d40SFabiano Rosas          * 32-bit subtraction and then a possible 32-bit saturating
7872f0984d40SFabiano Rosas          * addition of Ra.
7873f0984d40SFabiano Rosas          */
7874f0984d40SFabiano Rosas         tcg_gen_sub_i32(t1, t1, t2);
7875f0984d40SFabiano Rosas         tcg_temp_free_i32(t2);
7876f0984d40SFabiano Rosas 
7877f0984d40SFabiano Rosas         if (a->ra != 15) {
7878f0984d40SFabiano Rosas             t2 = load_reg(s, a->ra);
7879f0984d40SFabiano Rosas             gen_helper_add_setq(t1, cpu_env, t1, t2);
7880f0984d40SFabiano Rosas             tcg_temp_free_i32(t2);
7881f0984d40SFabiano Rosas         }
7882f0984d40SFabiano Rosas     } else if (a->ra == 15) {
7883f0984d40SFabiano Rosas         /* Single saturation-checking addition */
7884f0984d40SFabiano Rosas         gen_helper_add_setq(t1, cpu_env, t1, t2);
7885f0984d40SFabiano Rosas         tcg_temp_free_i32(t2);
7886f0984d40SFabiano Rosas     } else {
7887f0984d40SFabiano Rosas         /*
7888f0984d40SFabiano Rosas          * We need to add the products and Ra together and then
7889f0984d40SFabiano Rosas          * determine whether the final result overflowed. Doing
7890f0984d40SFabiano Rosas          * this as two separate add-and-check-overflow steps incorrectly
7891f0984d40SFabiano Rosas          * sets Q for cases like (-32768 * -32768) + (-32768 * -32768) + -1.
7892f0984d40SFabiano Rosas          * Do all the arithmetic at 64-bits and then check for overflow.
7893f0984d40SFabiano Rosas          */
7894f0984d40SFabiano Rosas         TCGv_i64 p64, q64;
7895f0984d40SFabiano Rosas         TCGv_i32 t3, qf, one;
7896f0984d40SFabiano Rosas 
7897f0984d40SFabiano Rosas         p64 = tcg_temp_new_i64();
7898f0984d40SFabiano Rosas         q64 = tcg_temp_new_i64();
7899f0984d40SFabiano Rosas         tcg_gen_ext_i32_i64(p64, t1);
7900f0984d40SFabiano Rosas         tcg_gen_ext_i32_i64(q64, t2);
7901f0984d40SFabiano Rosas         tcg_gen_add_i64(p64, p64, q64);
7902f0984d40SFabiano Rosas         load_reg_var(s, t2, a->ra);
7903f0984d40SFabiano Rosas         tcg_gen_ext_i32_i64(q64, t2);
7904f0984d40SFabiano Rosas         tcg_gen_add_i64(p64, p64, q64);
7905f0984d40SFabiano Rosas         tcg_temp_free_i64(q64);
7906f0984d40SFabiano Rosas 
7907f0984d40SFabiano Rosas         tcg_gen_extr_i64_i32(t1, t2, p64);
7908f0984d40SFabiano Rosas         tcg_temp_free_i64(p64);
7909f0984d40SFabiano Rosas         /*
7910f0984d40SFabiano Rosas          * t1 is the low half of the result which goes into Rd.
7911f0984d40SFabiano Rosas          * We have overflow and must set Q if the high half (t2)
7912f0984d40SFabiano Rosas          * is different from the sign-extension of t1.
7913f0984d40SFabiano Rosas          */
7914f0984d40SFabiano Rosas         t3 = tcg_temp_new_i32();
7915f0984d40SFabiano Rosas         tcg_gen_sari_i32(t3, t1, 31);
7916f0984d40SFabiano Rosas         qf = load_cpu_field(QF);
7917f0984d40SFabiano Rosas         one = tcg_constant_i32(1);
7918f0984d40SFabiano Rosas         tcg_gen_movcond_i32(TCG_COND_NE, qf, t2, t3, one, qf);
7919f0984d40SFabiano Rosas         store_cpu_field(qf, QF);
7920f0984d40SFabiano Rosas         tcg_temp_free_i32(t3);
7921f0984d40SFabiano Rosas         tcg_temp_free_i32(t2);
7922f0984d40SFabiano Rosas     }
7923f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
7924f0984d40SFabiano Rosas     return true;
7925f0984d40SFabiano Rosas }
7926f0984d40SFabiano Rosas 
7927f0984d40SFabiano Rosas static bool trans_SMLAD(DisasContext *s, arg_rrrr *a)
7928f0984d40SFabiano Rosas {
7929f0984d40SFabiano Rosas     return op_smlad(s, a, false, false);
7930f0984d40SFabiano Rosas }
7931f0984d40SFabiano Rosas 
7932f0984d40SFabiano Rosas static bool trans_SMLADX(DisasContext *s, arg_rrrr *a)
7933f0984d40SFabiano Rosas {
7934f0984d40SFabiano Rosas     return op_smlad(s, a, true, false);
7935f0984d40SFabiano Rosas }
7936f0984d40SFabiano Rosas 
7937f0984d40SFabiano Rosas static bool trans_SMLSD(DisasContext *s, arg_rrrr *a)
7938f0984d40SFabiano Rosas {
7939f0984d40SFabiano Rosas     return op_smlad(s, a, false, true);
7940f0984d40SFabiano Rosas }
7941f0984d40SFabiano Rosas 
7942f0984d40SFabiano Rosas static bool trans_SMLSDX(DisasContext *s, arg_rrrr *a)
7943f0984d40SFabiano Rosas {
7944f0984d40SFabiano Rosas     return op_smlad(s, a, true, true);
7945f0984d40SFabiano Rosas }
7946f0984d40SFabiano Rosas 
7947f0984d40SFabiano Rosas static bool op_smlald(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub)
7948f0984d40SFabiano Rosas {
7949f0984d40SFabiano Rosas     TCGv_i32 t1, t2;
7950f0984d40SFabiano Rosas     TCGv_i64 l1, l2;
7951f0984d40SFabiano Rosas 
7952f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
7953f0984d40SFabiano Rosas         return false;
7954f0984d40SFabiano Rosas     }
7955f0984d40SFabiano Rosas 
7956f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
7957f0984d40SFabiano Rosas     t2 = load_reg(s, a->rm);
7958f0984d40SFabiano Rosas     if (m_swap) {
7959f0984d40SFabiano Rosas         gen_swap_half(t2, t2);
7960f0984d40SFabiano Rosas     }
7961f0984d40SFabiano Rosas     gen_smul_dual(t1, t2);
7962f0984d40SFabiano Rosas 
7963f0984d40SFabiano Rosas     l1 = tcg_temp_new_i64();
7964f0984d40SFabiano Rosas     l2 = tcg_temp_new_i64();
7965f0984d40SFabiano Rosas     tcg_gen_ext_i32_i64(l1, t1);
7966f0984d40SFabiano Rosas     tcg_gen_ext_i32_i64(l2, t2);
7967f0984d40SFabiano Rosas     tcg_temp_free_i32(t1);
7968f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
7969f0984d40SFabiano Rosas 
7970f0984d40SFabiano Rosas     if (sub) {
7971f0984d40SFabiano Rosas         tcg_gen_sub_i64(l1, l1, l2);
7972f0984d40SFabiano Rosas     } else {
7973f0984d40SFabiano Rosas         tcg_gen_add_i64(l1, l1, l2);
7974f0984d40SFabiano Rosas     }
7975f0984d40SFabiano Rosas     tcg_temp_free_i64(l2);
7976f0984d40SFabiano Rosas 
7977f0984d40SFabiano Rosas     gen_addq(s, l1, a->ra, a->rd);
7978f0984d40SFabiano Rosas     gen_storeq_reg(s, a->ra, a->rd, l1);
7979f0984d40SFabiano Rosas     tcg_temp_free_i64(l1);
7980f0984d40SFabiano Rosas     return true;
7981f0984d40SFabiano Rosas }
7982f0984d40SFabiano Rosas 
7983f0984d40SFabiano Rosas static bool trans_SMLALD(DisasContext *s, arg_rrrr *a)
7984f0984d40SFabiano Rosas {
7985f0984d40SFabiano Rosas     return op_smlald(s, a, false, false);
7986f0984d40SFabiano Rosas }
7987f0984d40SFabiano Rosas 
7988f0984d40SFabiano Rosas static bool trans_SMLALDX(DisasContext *s, arg_rrrr *a)
7989f0984d40SFabiano Rosas {
7990f0984d40SFabiano Rosas     return op_smlald(s, a, true, false);
7991f0984d40SFabiano Rosas }
7992f0984d40SFabiano Rosas 
7993f0984d40SFabiano Rosas static bool trans_SMLSLD(DisasContext *s, arg_rrrr *a)
7994f0984d40SFabiano Rosas {
7995f0984d40SFabiano Rosas     return op_smlald(s, a, false, true);
7996f0984d40SFabiano Rosas }
7997f0984d40SFabiano Rosas 
7998f0984d40SFabiano Rosas static bool trans_SMLSLDX(DisasContext *s, arg_rrrr *a)
7999f0984d40SFabiano Rosas {
8000f0984d40SFabiano Rosas     return op_smlald(s, a, true, true);
8001f0984d40SFabiano Rosas }
8002f0984d40SFabiano Rosas 
8003f0984d40SFabiano Rosas static bool op_smmla(DisasContext *s, arg_rrrr *a, bool round, bool sub)
8004f0984d40SFabiano Rosas {
8005f0984d40SFabiano Rosas     TCGv_i32 t1, t2;
8006f0984d40SFabiano Rosas 
8007f0984d40SFabiano Rosas     if (s->thumb
8008f0984d40SFabiano Rosas         ? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
8009f0984d40SFabiano Rosas         : !ENABLE_ARCH_6) {
8010f0984d40SFabiano Rosas         return false;
8011f0984d40SFabiano Rosas     }
8012f0984d40SFabiano Rosas 
8013f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
8014f0984d40SFabiano Rosas     t2 = load_reg(s, a->rm);
8015f0984d40SFabiano Rosas     tcg_gen_muls2_i32(t2, t1, t1, t2);
8016f0984d40SFabiano Rosas 
8017f0984d40SFabiano Rosas     if (a->ra != 15) {
8018f0984d40SFabiano Rosas         TCGv_i32 t3 = load_reg(s, a->ra);
8019f0984d40SFabiano Rosas         if (sub) {
8020f0984d40SFabiano Rosas             /*
8021f0984d40SFabiano Rosas              * For SMMLS, we need a 64-bit subtract.  Borrow caused by
8022f0984d40SFabiano Rosas              * a non-zero multiplicand lowpart, and the correct result
8023f0984d40SFabiano Rosas              * lowpart for rounding.
8024f0984d40SFabiano Rosas              */
8025f0984d40SFabiano Rosas             tcg_gen_sub2_i32(t2, t1, tcg_constant_i32(0), t3, t2, t1);
8026f0984d40SFabiano Rosas         } else {
8027f0984d40SFabiano Rosas             tcg_gen_add_i32(t1, t1, t3);
8028f0984d40SFabiano Rosas         }
8029f0984d40SFabiano Rosas         tcg_temp_free_i32(t3);
8030f0984d40SFabiano Rosas     }
8031f0984d40SFabiano Rosas     if (round) {
8032f0984d40SFabiano Rosas         /*
8033f0984d40SFabiano Rosas          * Adding 0x80000000 to the 64-bit quantity means that we have
8034f0984d40SFabiano Rosas          * carry in to the high word when the low word has the msb set.
8035f0984d40SFabiano Rosas          */
8036f0984d40SFabiano Rosas         tcg_gen_shri_i32(t2, t2, 31);
8037f0984d40SFabiano Rosas         tcg_gen_add_i32(t1, t1, t2);
8038f0984d40SFabiano Rosas     }
8039f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
8040f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
8041f0984d40SFabiano Rosas     return true;
8042f0984d40SFabiano Rosas }
8043f0984d40SFabiano Rosas 
8044f0984d40SFabiano Rosas static bool trans_SMMLA(DisasContext *s, arg_rrrr *a)
8045f0984d40SFabiano Rosas {
8046f0984d40SFabiano Rosas     return op_smmla(s, a, false, false);
8047f0984d40SFabiano Rosas }
8048f0984d40SFabiano Rosas 
8049f0984d40SFabiano Rosas static bool trans_SMMLAR(DisasContext *s, arg_rrrr *a)
8050f0984d40SFabiano Rosas {
8051f0984d40SFabiano Rosas     return op_smmla(s, a, true, false);
8052f0984d40SFabiano Rosas }
8053f0984d40SFabiano Rosas 
8054f0984d40SFabiano Rosas static bool trans_SMMLS(DisasContext *s, arg_rrrr *a)
8055f0984d40SFabiano Rosas {
8056f0984d40SFabiano Rosas     return op_smmla(s, a, false, true);
8057f0984d40SFabiano Rosas }
8058f0984d40SFabiano Rosas 
8059f0984d40SFabiano Rosas static bool trans_SMMLSR(DisasContext *s, arg_rrrr *a)
8060f0984d40SFabiano Rosas {
8061f0984d40SFabiano Rosas     return op_smmla(s, a, true, true);
8062f0984d40SFabiano Rosas }
8063f0984d40SFabiano Rosas 
8064f0984d40SFabiano Rosas static bool op_div(DisasContext *s, arg_rrr *a, bool u)
8065f0984d40SFabiano Rosas {
8066f0984d40SFabiano Rosas     TCGv_i32 t1, t2;
8067f0984d40SFabiano Rosas 
8068f0984d40SFabiano Rosas     if (s->thumb
8069f0984d40SFabiano Rosas         ? !dc_isar_feature(aa32_thumb_div, s)
8070f0984d40SFabiano Rosas         : !dc_isar_feature(aa32_arm_div, s)) {
8071f0984d40SFabiano Rosas         return false;
8072f0984d40SFabiano Rosas     }
8073f0984d40SFabiano Rosas 
8074f0984d40SFabiano Rosas     t1 = load_reg(s, a->rn);
8075f0984d40SFabiano Rosas     t2 = load_reg(s, a->rm);
8076f0984d40SFabiano Rosas     if (u) {
8077f0984d40SFabiano Rosas         gen_helper_udiv(t1, cpu_env, t1, t2);
8078f0984d40SFabiano Rosas     } else {
8079f0984d40SFabiano Rosas         gen_helper_sdiv(t1, cpu_env, t1, t2);
8080f0984d40SFabiano Rosas     }
8081f0984d40SFabiano Rosas     tcg_temp_free_i32(t2);
8082f0984d40SFabiano Rosas     store_reg(s, a->rd, t1);
8083f0984d40SFabiano Rosas     return true;
8084f0984d40SFabiano Rosas }
8085f0984d40SFabiano Rosas 
8086f0984d40SFabiano Rosas static bool trans_SDIV(DisasContext *s, arg_rrr *a)
8087f0984d40SFabiano Rosas {
8088f0984d40SFabiano Rosas     return op_div(s, a, false);
8089f0984d40SFabiano Rosas }
8090f0984d40SFabiano Rosas 
8091f0984d40SFabiano Rosas static bool trans_UDIV(DisasContext *s, arg_rrr *a)
8092f0984d40SFabiano Rosas {
8093f0984d40SFabiano Rosas     return op_div(s, a, true);
8094f0984d40SFabiano Rosas }
8095f0984d40SFabiano Rosas 
8096f0984d40SFabiano Rosas /*
8097f0984d40SFabiano Rosas  * Block data transfer
8098f0984d40SFabiano Rosas  */
8099f0984d40SFabiano Rosas 
8100f0984d40SFabiano Rosas static TCGv_i32 op_addr_block_pre(DisasContext *s, arg_ldst_block *a, int n)
8101f0984d40SFabiano Rosas {
8102f0984d40SFabiano Rosas     TCGv_i32 addr = load_reg(s, a->rn);
8103f0984d40SFabiano Rosas 
8104f0984d40SFabiano Rosas     if (a->b) {
8105f0984d40SFabiano Rosas         if (a->i) {
8106f0984d40SFabiano Rosas             /* pre increment */
8107f0984d40SFabiano Rosas             tcg_gen_addi_i32(addr, addr, 4);
8108f0984d40SFabiano Rosas         } else {
8109f0984d40SFabiano Rosas             /* pre decrement */
8110f0984d40SFabiano Rosas             tcg_gen_addi_i32(addr, addr, -(n * 4));
8111f0984d40SFabiano Rosas         }
8112f0984d40SFabiano Rosas     } else if (!a->i && n != 1) {
8113f0984d40SFabiano Rosas         /* post decrement */
8114f0984d40SFabiano Rosas         tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
8115f0984d40SFabiano Rosas     }
8116f0984d40SFabiano Rosas 
8117f0984d40SFabiano Rosas     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
8118f0984d40SFabiano Rosas         /*
8119f0984d40SFabiano Rosas          * If the writeback is incrementing SP rather than
8120f0984d40SFabiano Rosas          * decrementing it, and the initial SP is below the
8121f0984d40SFabiano Rosas          * stack limit but the final written-back SP would
8122f0984d40SFabiano Rosas          * be above, then we must not perform any memory
8123f0984d40SFabiano Rosas          * accesses, but it is IMPDEF whether we generate
8124f0984d40SFabiano Rosas          * an exception. We choose to do so in this case.
8125f0984d40SFabiano Rosas          * At this point 'addr' is the lowest address, so
8126f0984d40SFabiano Rosas          * either the original SP (if incrementing) or our
8127f0984d40SFabiano Rosas          * final SP (if decrementing), so that's what we check.
8128f0984d40SFabiano Rosas          */
8129f0984d40SFabiano Rosas         gen_helper_v8m_stackcheck(cpu_env, addr);
8130f0984d40SFabiano Rosas     }
8131f0984d40SFabiano Rosas 
8132f0984d40SFabiano Rosas     return addr;
8133f0984d40SFabiano Rosas }
8134f0984d40SFabiano Rosas 
8135f0984d40SFabiano Rosas static void op_addr_block_post(DisasContext *s, arg_ldst_block *a,
8136f0984d40SFabiano Rosas                                TCGv_i32 addr, int n)
8137f0984d40SFabiano Rosas {
8138f0984d40SFabiano Rosas     if (a->w) {
8139f0984d40SFabiano Rosas         /* write back */
8140f0984d40SFabiano Rosas         if (!a->b) {
8141f0984d40SFabiano Rosas             if (a->i) {
8142f0984d40SFabiano Rosas                 /* post increment */
8143f0984d40SFabiano Rosas                 tcg_gen_addi_i32(addr, addr, 4);
8144f0984d40SFabiano Rosas             } else {
8145f0984d40SFabiano Rosas                 /* post decrement */
8146f0984d40SFabiano Rosas                 tcg_gen_addi_i32(addr, addr, -(n * 4));
8147f0984d40SFabiano Rosas             }
8148f0984d40SFabiano Rosas         } else if (!a->i && n != 1) {
8149f0984d40SFabiano Rosas             /* pre decrement */
8150f0984d40SFabiano Rosas             tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
8151f0984d40SFabiano Rosas         }
8152f0984d40SFabiano Rosas         store_reg(s, a->rn, addr);
8153f0984d40SFabiano Rosas     } else {
8154f0984d40SFabiano Rosas         tcg_temp_free_i32(addr);
8155f0984d40SFabiano Rosas     }
8156f0984d40SFabiano Rosas }
8157f0984d40SFabiano Rosas 
8158f0984d40SFabiano Rosas static bool op_stm(DisasContext *s, arg_ldst_block *a, int min_n)
8159f0984d40SFabiano Rosas {
8160f0984d40SFabiano Rosas     int i, j, n, list, mem_idx;
8161f0984d40SFabiano Rosas     bool user = a->u;
8162f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
8163f0984d40SFabiano Rosas 
8164f0984d40SFabiano Rosas     if (user) {
8165f0984d40SFabiano Rosas         /* STM (user) */
8166f0984d40SFabiano Rosas         if (IS_USER(s)) {
8167f0984d40SFabiano Rosas             /* Only usable in supervisor mode.  */
8168f0984d40SFabiano Rosas             unallocated_encoding(s);
8169f0984d40SFabiano Rosas             return true;
8170f0984d40SFabiano Rosas         }
8171f0984d40SFabiano Rosas     }
8172f0984d40SFabiano Rosas 
8173f0984d40SFabiano Rosas     list = a->list;
8174f0984d40SFabiano Rosas     n = ctpop16(list);
8175f0984d40SFabiano Rosas     if (n < min_n || a->rn == 15) {
8176f0984d40SFabiano Rosas         unallocated_encoding(s);
8177f0984d40SFabiano Rosas         return true;
8178f0984d40SFabiano Rosas     }
8179f0984d40SFabiano Rosas 
8180f0984d40SFabiano Rosas     s->eci_handled = true;
8181f0984d40SFabiano Rosas 
8182f0984d40SFabiano Rosas     addr = op_addr_block_pre(s, a, n);
8183f0984d40SFabiano Rosas     mem_idx = get_mem_index(s);
8184f0984d40SFabiano Rosas 
8185f0984d40SFabiano Rosas     for (i = j = 0; i < 16; i++) {
8186f0984d40SFabiano Rosas         if (!(list & (1 << i))) {
8187f0984d40SFabiano Rosas             continue;
8188f0984d40SFabiano Rosas         }
8189f0984d40SFabiano Rosas 
8190f0984d40SFabiano Rosas         if (user && i != 15) {
8191f0984d40SFabiano Rosas             tmp = tcg_temp_new_i32();
8192f0984d40SFabiano Rosas             gen_helper_get_user_reg(tmp, cpu_env, tcg_constant_i32(i));
8193f0984d40SFabiano Rosas         } else {
8194f0984d40SFabiano Rosas             tmp = load_reg(s, i);
8195f0984d40SFabiano Rosas         }
8196f0984d40SFabiano Rosas         gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
8197f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
8198f0984d40SFabiano Rosas 
8199f0984d40SFabiano Rosas         /* No need to add after the last transfer.  */
8200f0984d40SFabiano Rosas         if (++j != n) {
8201f0984d40SFabiano Rosas             tcg_gen_addi_i32(addr, addr, 4);
8202f0984d40SFabiano Rosas         }
8203f0984d40SFabiano Rosas     }
8204f0984d40SFabiano Rosas 
8205f0984d40SFabiano Rosas     op_addr_block_post(s, a, addr, n);
8206f0984d40SFabiano Rosas     clear_eci_state(s);
8207f0984d40SFabiano Rosas     return true;
8208f0984d40SFabiano Rosas }
8209f0984d40SFabiano Rosas 
8210f0984d40SFabiano Rosas static bool trans_STM(DisasContext *s, arg_ldst_block *a)
8211f0984d40SFabiano Rosas {
8212f0984d40SFabiano Rosas     /* BitCount(list) < 1 is UNPREDICTABLE */
8213f0984d40SFabiano Rosas     return op_stm(s, a, 1);
8214f0984d40SFabiano Rosas }
8215f0984d40SFabiano Rosas 
8216f0984d40SFabiano Rosas static bool trans_STM_t32(DisasContext *s, arg_ldst_block *a)
8217f0984d40SFabiano Rosas {
8218f0984d40SFabiano Rosas     /* Writeback register in register list is UNPREDICTABLE for T32.  */
8219f0984d40SFabiano Rosas     if (a->w && (a->list & (1 << a->rn))) {
8220f0984d40SFabiano Rosas         unallocated_encoding(s);
8221f0984d40SFabiano Rosas         return true;
8222f0984d40SFabiano Rosas     }
8223f0984d40SFabiano Rosas     /* BitCount(list) < 2 is UNPREDICTABLE */
8224f0984d40SFabiano Rosas     return op_stm(s, a, 2);
8225f0984d40SFabiano Rosas }
8226f0984d40SFabiano Rosas 
8227f0984d40SFabiano Rosas static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n)
8228f0984d40SFabiano Rosas {
8229f0984d40SFabiano Rosas     int i, j, n, list, mem_idx;
8230f0984d40SFabiano Rosas     bool loaded_base;
8231f0984d40SFabiano Rosas     bool user = a->u;
8232f0984d40SFabiano Rosas     bool exc_return = false;
8233f0984d40SFabiano Rosas     TCGv_i32 addr, tmp, loaded_var;
8234f0984d40SFabiano Rosas 
8235f0984d40SFabiano Rosas     if (user) {
8236f0984d40SFabiano Rosas         /* LDM (user), LDM (exception return) */
8237f0984d40SFabiano Rosas         if (IS_USER(s)) {
8238f0984d40SFabiano Rosas             /* Only usable in supervisor mode.  */
8239f0984d40SFabiano Rosas             unallocated_encoding(s);
8240f0984d40SFabiano Rosas             return true;
8241f0984d40SFabiano Rosas         }
8242f0984d40SFabiano Rosas         if (extract32(a->list, 15, 1)) {
8243f0984d40SFabiano Rosas             exc_return = true;
8244f0984d40SFabiano Rosas             user = false;
8245f0984d40SFabiano Rosas         } else {
8246f0984d40SFabiano Rosas             /* LDM (user) does not allow writeback.  */
8247f0984d40SFabiano Rosas             if (a->w) {
8248f0984d40SFabiano Rosas                 unallocated_encoding(s);
8249f0984d40SFabiano Rosas                 return true;
8250f0984d40SFabiano Rosas             }
8251f0984d40SFabiano Rosas         }
8252f0984d40SFabiano Rosas     }
8253f0984d40SFabiano Rosas 
8254f0984d40SFabiano Rosas     list = a->list;
8255f0984d40SFabiano Rosas     n = ctpop16(list);
8256f0984d40SFabiano Rosas     if (n < min_n || a->rn == 15) {
8257f0984d40SFabiano Rosas         unallocated_encoding(s);
8258f0984d40SFabiano Rosas         return true;
8259f0984d40SFabiano Rosas     }
8260f0984d40SFabiano Rosas 
8261f0984d40SFabiano Rosas     s->eci_handled = true;
8262f0984d40SFabiano Rosas 
8263f0984d40SFabiano Rosas     addr = op_addr_block_pre(s, a, n);
8264f0984d40SFabiano Rosas     mem_idx = get_mem_index(s);
8265f0984d40SFabiano Rosas     loaded_base = false;
8266f0984d40SFabiano Rosas     loaded_var = NULL;
8267f0984d40SFabiano Rosas 
8268f0984d40SFabiano Rosas     for (i = j = 0; i < 16; i++) {
8269f0984d40SFabiano Rosas         if (!(list & (1 << i))) {
8270f0984d40SFabiano Rosas             continue;
8271f0984d40SFabiano Rosas         }
8272f0984d40SFabiano Rosas 
8273f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
8274f0984d40SFabiano Rosas         gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
8275f0984d40SFabiano Rosas         if (user) {
8276f0984d40SFabiano Rosas             gen_helper_set_user_reg(cpu_env, tcg_constant_i32(i), tmp);
8277f0984d40SFabiano Rosas             tcg_temp_free_i32(tmp);
8278f0984d40SFabiano Rosas         } else if (i == a->rn) {
8279f0984d40SFabiano Rosas             loaded_var = tmp;
8280f0984d40SFabiano Rosas             loaded_base = true;
8281f0984d40SFabiano Rosas         } else if (i == 15 && exc_return) {
8282f0984d40SFabiano Rosas             store_pc_exc_ret(s, tmp);
8283f0984d40SFabiano Rosas         } else {
8284f0984d40SFabiano Rosas             store_reg_from_load(s, i, tmp);
8285f0984d40SFabiano Rosas         }
8286f0984d40SFabiano Rosas 
8287f0984d40SFabiano Rosas         /* No need to add after the last transfer.  */
8288f0984d40SFabiano Rosas         if (++j != n) {
8289f0984d40SFabiano Rosas             tcg_gen_addi_i32(addr, addr, 4);
8290f0984d40SFabiano Rosas         }
8291f0984d40SFabiano Rosas     }
8292f0984d40SFabiano Rosas 
8293f0984d40SFabiano Rosas     op_addr_block_post(s, a, addr, n);
8294f0984d40SFabiano Rosas 
8295f0984d40SFabiano Rosas     if (loaded_base) {
8296f0984d40SFabiano Rosas         /* Note that we reject base == pc above.  */
8297f0984d40SFabiano Rosas         store_reg(s, a->rn, loaded_var);
8298f0984d40SFabiano Rosas     }
8299f0984d40SFabiano Rosas 
8300f0984d40SFabiano Rosas     if (exc_return) {
8301f0984d40SFabiano Rosas         /* Restore CPSR from SPSR.  */
8302f0984d40SFabiano Rosas         tmp = load_cpu_field(spsr);
8303f0984d40SFabiano Rosas         if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
8304f0984d40SFabiano Rosas             gen_io_start();
8305f0984d40SFabiano Rosas         }
8306f0984d40SFabiano Rosas         gen_helper_cpsr_write_eret(cpu_env, tmp);
8307f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
8308f0984d40SFabiano Rosas         /* Must exit loop to check un-masked IRQs */
8309f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_EXIT;
8310f0984d40SFabiano Rosas     }
8311f0984d40SFabiano Rosas     clear_eci_state(s);
8312f0984d40SFabiano Rosas     return true;
8313f0984d40SFabiano Rosas }
8314f0984d40SFabiano Rosas 
8315f0984d40SFabiano Rosas static bool trans_LDM_a32(DisasContext *s, arg_ldst_block *a)
8316f0984d40SFabiano Rosas {
8317f0984d40SFabiano Rosas     /*
8318f0984d40SFabiano Rosas      * Writeback register in register list is UNPREDICTABLE
8319f0984d40SFabiano Rosas      * for ArchVersion() >= 7.  Prior to v7, A32 would write
8320f0984d40SFabiano Rosas      * an UNKNOWN value to the base register.
8321f0984d40SFabiano Rosas      */
8322f0984d40SFabiano Rosas     if (ENABLE_ARCH_7 && a->w && (a->list & (1 << a->rn))) {
8323f0984d40SFabiano Rosas         unallocated_encoding(s);
8324f0984d40SFabiano Rosas         return true;
8325f0984d40SFabiano Rosas     }
8326f0984d40SFabiano Rosas     /* BitCount(list) < 1 is UNPREDICTABLE */
8327f0984d40SFabiano Rosas     return do_ldm(s, a, 1);
8328f0984d40SFabiano Rosas }
8329f0984d40SFabiano Rosas 
8330f0984d40SFabiano Rosas static bool trans_LDM_t32(DisasContext *s, arg_ldst_block *a)
8331f0984d40SFabiano Rosas {
8332f0984d40SFabiano Rosas     /* Writeback register in register list is UNPREDICTABLE for T32. */
8333f0984d40SFabiano Rosas     if (a->w && (a->list & (1 << a->rn))) {
8334f0984d40SFabiano Rosas         unallocated_encoding(s);
8335f0984d40SFabiano Rosas         return true;
8336f0984d40SFabiano Rosas     }
8337f0984d40SFabiano Rosas     /* BitCount(list) < 2 is UNPREDICTABLE */
8338f0984d40SFabiano Rosas     return do_ldm(s, a, 2);
8339f0984d40SFabiano Rosas }
8340f0984d40SFabiano Rosas 
8341f0984d40SFabiano Rosas static bool trans_LDM_t16(DisasContext *s, arg_ldst_block *a)
8342f0984d40SFabiano Rosas {
8343f0984d40SFabiano Rosas     /* Writeback is conditional on the base register not being loaded.  */
8344f0984d40SFabiano Rosas     a->w = !(a->list & (1 << a->rn));
8345f0984d40SFabiano Rosas     /* BitCount(list) < 1 is UNPREDICTABLE */
8346f0984d40SFabiano Rosas     return do_ldm(s, a, 1);
8347f0984d40SFabiano Rosas }
8348f0984d40SFabiano Rosas 
8349f0984d40SFabiano Rosas static bool trans_CLRM(DisasContext *s, arg_CLRM *a)
8350f0984d40SFabiano Rosas {
8351f0984d40SFabiano Rosas     int i;
8352f0984d40SFabiano Rosas     TCGv_i32 zero;
8353f0984d40SFabiano Rosas 
8354f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_m_sec_state, s)) {
8355f0984d40SFabiano Rosas         return false;
8356f0984d40SFabiano Rosas     }
8357f0984d40SFabiano Rosas 
8358f0984d40SFabiano Rosas     if (extract32(a->list, 13, 1)) {
8359f0984d40SFabiano Rosas         return false;
8360f0984d40SFabiano Rosas     }
8361f0984d40SFabiano Rosas 
8362f0984d40SFabiano Rosas     if (!a->list) {
8363f0984d40SFabiano Rosas         /* UNPREDICTABLE; we choose to UNDEF */
8364f0984d40SFabiano Rosas         return false;
8365f0984d40SFabiano Rosas     }
8366f0984d40SFabiano Rosas 
8367f0984d40SFabiano Rosas     s->eci_handled = true;
8368f0984d40SFabiano Rosas 
8369f0984d40SFabiano Rosas     zero = tcg_constant_i32(0);
8370f0984d40SFabiano Rosas     for (i = 0; i < 15; i++) {
8371f0984d40SFabiano Rosas         if (extract32(a->list, i, 1)) {
8372f0984d40SFabiano Rosas             /* Clear R[i] */
8373f0984d40SFabiano Rosas             tcg_gen_mov_i32(cpu_R[i], zero);
8374f0984d40SFabiano Rosas         }
8375f0984d40SFabiano Rosas     }
8376f0984d40SFabiano Rosas     if (extract32(a->list, 15, 1)) {
8377f0984d40SFabiano Rosas         /*
8378f0984d40SFabiano Rosas          * Clear APSR (by calling the MSR helper with the same argument
8379f0984d40SFabiano Rosas          * as for "MSR APSR_nzcvqg, Rn": mask = 0b1100, SYSM=0)
8380f0984d40SFabiano Rosas          */
8381f0984d40SFabiano Rosas         gen_helper_v7m_msr(cpu_env, tcg_constant_i32(0xc00), zero);
8382f0984d40SFabiano Rosas     }
8383f0984d40SFabiano Rosas     clear_eci_state(s);
8384f0984d40SFabiano Rosas     return true;
8385f0984d40SFabiano Rosas }
8386f0984d40SFabiano Rosas 
8387f0984d40SFabiano Rosas /*
8388f0984d40SFabiano Rosas  * Branch, branch with link
8389f0984d40SFabiano Rosas  */
8390f0984d40SFabiano Rosas 
8391f0984d40SFabiano Rosas static bool trans_B(DisasContext *s, arg_i *a)
8392f0984d40SFabiano Rosas {
8393f0984d40SFabiano Rosas     gen_jmp(s, jmp_diff(s, a->imm));
8394f0984d40SFabiano Rosas     return true;
8395f0984d40SFabiano Rosas }
8396f0984d40SFabiano Rosas 
8397f0984d40SFabiano Rosas static bool trans_B_cond_thumb(DisasContext *s, arg_ci *a)
8398f0984d40SFabiano Rosas {
8399f0984d40SFabiano Rosas     /* This has cond from encoding, required to be outside IT block.  */
8400f0984d40SFabiano Rosas     if (a->cond >= 0xe) {
8401f0984d40SFabiano Rosas         return false;
8402f0984d40SFabiano Rosas     }
8403f0984d40SFabiano Rosas     if (s->condexec_mask) {
8404f0984d40SFabiano Rosas         unallocated_encoding(s);
8405f0984d40SFabiano Rosas         return true;
8406f0984d40SFabiano Rosas     }
8407f0984d40SFabiano Rosas     arm_skip_unless(s, a->cond);
8408f0984d40SFabiano Rosas     gen_jmp(s, jmp_diff(s, a->imm));
8409f0984d40SFabiano Rosas     return true;
8410f0984d40SFabiano Rosas }
8411f0984d40SFabiano Rosas 
8412f0984d40SFabiano Rosas static bool trans_BL(DisasContext *s, arg_i *a)
8413f0984d40SFabiano Rosas {
8414f0984d40SFabiano Rosas     gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
8415f0984d40SFabiano Rosas     gen_jmp(s, jmp_diff(s, a->imm));
8416f0984d40SFabiano Rosas     return true;
8417f0984d40SFabiano Rosas }
8418f0984d40SFabiano Rosas 
8419f0984d40SFabiano Rosas static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
8420f0984d40SFabiano Rosas {
8421f0984d40SFabiano Rosas     /*
8422f0984d40SFabiano Rosas      * BLX <imm> would be useless on M-profile; the encoding space
8423f0984d40SFabiano Rosas      * is used for other insns from v8.1M onward, and UNDEFs before that.
8424f0984d40SFabiano Rosas      */
8425f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M)) {
8426f0984d40SFabiano Rosas         return false;
8427f0984d40SFabiano Rosas     }
8428f0984d40SFabiano Rosas 
8429f0984d40SFabiano Rosas     /* For A32, ARM_FEATURE_V5 is checked near the start of the uncond block. */
8430f0984d40SFabiano Rosas     if (s->thumb && (a->imm & 2)) {
8431f0984d40SFabiano Rosas         return false;
8432f0984d40SFabiano Rosas     }
8433f0984d40SFabiano Rosas     gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
8434f0984d40SFabiano Rosas     store_cpu_field_constant(!s->thumb, thumb);
8435f0984d40SFabiano Rosas     /* This jump is computed from an aligned PC: subtract off the low bits. */
8436f0984d40SFabiano Rosas     gen_jmp(s, jmp_diff(s, a->imm - (s->pc_curr & 3)));
8437f0984d40SFabiano Rosas     return true;
8438f0984d40SFabiano Rosas }
8439f0984d40SFabiano Rosas 
8440f0984d40SFabiano Rosas static bool trans_BL_BLX_prefix(DisasContext *s, arg_BL_BLX_prefix *a)
8441f0984d40SFabiano Rosas {
8442f0984d40SFabiano Rosas     assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
8443f0984d40SFabiano Rosas     gen_pc_plus_diff(s, cpu_R[14], jmp_diff(s, a->imm << 12));
8444f0984d40SFabiano Rosas     return true;
8445f0984d40SFabiano Rosas }
8446f0984d40SFabiano Rosas 
8447f0984d40SFabiano Rosas static bool trans_BL_suffix(DisasContext *s, arg_BL_suffix *a)
8448f0984d40SFabiano Rosas {
8449f0984d40SFabiano Rosas     TCGv_i32 tmp = tcg_temp_new_i32();
8450f0984d40SFabiano Rosas 
8451f0984d40SFabiano Rosas     assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
8452f0984d40SFabiano Rosas     tcg_gen_addi_i32(tmp, cpu_R[14], (a->imm << 1) | 1);
8453f0984d40SFabiano Rosas     gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | 1);
8454f0984d40SFabiano Rosas     gen_bx(s, tmp);
8455f0984d40SFabiano Rosas     return true;
8456f0984d40SFabiano Rosas }
8457f0984d40SFabiano Rosas 
8458f0984d40SFabiano Rosas static bool trans_BLX_suffix(DisasContext *s, arg_BLX_suffix *a)
8459f0984d40SFabiano Rosas {
8460f0984d40SFabiano Rosas     TCGv_i32 tmp;
8461f0984d40SFabiano Rosas 
8462f0984d40SFabiano Rosas     assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
8463f0984d40SFabiano Rosas     if (!ENABLE_ARCH_5) {
8464f0984d40SFabiano Rosas         return false;
8465f0984d40SFabiano Rosas     }
8466f0984d40SFabiano Rosas     tmp = tcg_temp_new_i32();
8467f0984d40SFabiano Rosas     tcg_gen_addi_i32(tmp, cpu_R[14], a->imm << 1);
8468f0984d40SFabiano Rosas     tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
8469f0984d40SFabiano Rosas     gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | 1);
8470f0984d40SFabiano Rosas     gen_bx(s, tmp);
8471f0984d40SFabiano Rosas     return true;
8472f0984d40SFabiano Rosas }
8473f0984d40SFabiano Rosas 
8474f0984d40SFabiano Rosas static bool trans_BF(DisasContext *s, arg_BF *a)
8475f0984d40SFabiano Rosas {
8476f0984d40SFabiano Rosas     /*
8477f0984d40SFabiano Rosas      * M-profile branch future insns. The architecture permits an
8478f0984d40SFabiano Rosas      * implementation to implement these as NOPs (equivalent to
8479f0984d40SFabiano Rosas      * discarding the LO_BRANCH_INFO cache immediately), and we
8480f0984d40SFabiano Rosas      * take that IMPDEF option because for QEMU a "real" implementation
8481f0984d40SFabiano Rosas      * would be complicated and wouldn't execute any faster.
8482f0984d40SFabiano Rosas      */
8483f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_lob, s)) {
8484f0984d40SFabiano Rosas         return false;
8485f0984d40SFabiano Rosas     }
8486f0984d40SFabiano Rosas     if (a->boff == 0) {
8487f0984d40SFabiano Rosas         /* SEE "Related encodings" (loop insns) */
8488f0984d40SFabiano Rosas         return false;
8489f0984d40SFabiano Rosas     }
8490f0984d40SFabiano Rosas     /* Handle as NOP */
8491f0984d40SFabiano Rosas     return true;
8492f0984d40SFabiano Rosas }
8493f0984d40SFabiano Rosas 
8494f0984d40SFabiano Rosas static bool trans_DLS(DisasContext *s, arg_DLS *a)
8495f0984d40SFabiano Rosas {
8496f0984d40SFabiano Rosas     /* M-profile low-overhead loop start */
8497f0984d40SFabiano Rosas     TCGv_i32 tmp;
8498f0984d40SFabiano Rosas 
8499f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_lob, s)) {
8500f0984d40SFabiano Rosas         return false;
8501f0984d40SFabiano Rosas     }
8502f0984d40SFabiano Rosas     if (a->rn == 13 || a->rn == 15) {
8503f0984d40SFabiano Rosas         /*
8504f0984d40SFabiano Rosas          * For DLSTP rn == 15 is a related encoding (LCTP); the
8505f0984d40SFabiano Rosas          * other cases caught by this condition are all
8506f0984d40SFabiano Rosas          * CONSTRAINED UNPREDICTABLE: we choose to UNDEF
8507f0984d40SFabiano Rosas          */
8508f0984d40SFabiano Rosas         return false;
8509f0984d40SFabiano Rosas     }
8510f0984d40SFabiano Rosas 
8511f0984d40SFabiano Rosas     if (a->size != 4) {
8512f0984d40SFabiano Rosas         /* DLSTP */
8513f0984d40SFabiano Rosas         if (!dc_isar_feature(aa32_mve, s)) {
8514f0984d40SFabiano Rosas             return false;
8515f0984d40SFabiano Rosas         }
8516f0984d40SFabiano Rosas         if (!vfp_access_check(s)) {
8517f0984d40SFabiano Rosas             return true;
8518f0984d40SFabiano Rosas         }
8519f0984d40SFabiano Rosas     }
8520f0984d40SFabiano Rosas 
8521f0984d40SFabiano Rosas     /* Not a while loop: set LR to the count, and set LTPSIZE for DLSTP */
8522f0984d40SFabiano Rosas     tmp = load_reg(s, a->rn);
8523f0984d40SFabiano Rosas     store_reg(s, 14, tmp);
8524f0984d40SFabiano Rosas     if (a->size != 4) {
8525f0984d40SFabiano Rosas         /* DLSTP: set FPSCR.LTPSIZE */
8526f0984d40SFabiano Rosas         store_cpu_field(tcg_constant_i32(a->size), v7m.ltpsize);
8527f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
8528f0984d40SFabiano Rosas     }
8529f0984d40SFabiano Rosas     return true;
8530f0984d40SFabiano Rosas }
8531f0984d40SFabiano Rosas 
8532f0984d40SFabiano Rosas static bool trans_WLS(DisasContext *s, arg_WLS *a)
8533f0984d40SFabiano Rosas {
8534f0984d40SFabiano Rosas     /* M-profile low-overhead while-loop start */
8535f0984d40SFabiano Rosas     TCGv_i32 tmp;
8536f0984d40SFabiano Rosas     DisasLabel nextlabel;
8537f0984d40SFabiano Rosas 
8538f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_lob, s)) {
8539f0984d40SFabiano Rosas         return false;
8540f0984d40SFabiano Rosas     }
8541f0984d40SFabiano Rosas     if (a->rn == 13 || a->rn == 15) {
8542f0984d40SFabiano Rosas         /*
8543f0984d40SFabiano Rosas          * For WLSTP rn == 15 is a related encoding (LE); the
8544f0984d40SFabiano Rosas          * other cases caught by this condition are all
8545f0984d40SFabiano Rosas          * CONSTRAINED UNPREDICTABLE: we choose to UNDEF
8546f0984d40SFabiano Rosas          */
8547f0984d40SFabiano Rosas         return false;
8548f0984d40SFabiano Rosas     }
8549f0984d40SFabiano Rosas     if (s->condexec_mask) {
8550f0984d40SFabiano Rosas         /*
8551f0984d40SFabiano Rosas          * WLS in an IT block is CONSTRAINED UNPREDICTABLE;
8552f0984d40SFabiano Rosas          * we choose to UNDEF, because otherwise our use of
8553f0984d40SFabiano Rosas          * gen_goto_tb(1) would clash with the use of TB exit 1
8554f0984d40SFabiano Rosas          * in the dc->condjmp condition-failed codepath in
8555f0984d40SFabiano Rosas          * arm_tr_tb_stop() and we'd get an assertion.
8556f0984d40SFabiano Rosas          */
8557f0984d40SFabiano Rosas         return false;
8558f0984d40SFabiano Rosas     }
8559f0984d40SFabiano Rosas     if (a->size != 4) {
8560f0984d40SFabiano Rosas         /* WLSTP */
8561f0984d40SFabiano Rosas         if (!dc_isar_feature(aa32_mve, s)) {
8562f0984d40SFabiano Rosas             return false;
8563f0984d40SFabiano Rosas         }
8564f0984d40SFabiano Rosas         /*
8565f0984d40SFabiano Rosas          * We need to check that the FPU is enabled here, but mustn't
8566f0984d40SFabiano Rosas          * call vfp_access_check() to do that because we don't want to
8567f0984d40SFabiano Rosas          * do the lazy state preservation in the "loop count is zero" case.
8568f0984d40SFabiano Rosas          * Do the check-and-raise-exception by hand.
8569f0984d40SFabiano Rosas          */
8570f0984d40SFabiano Rosas         if (s->fp_excp_el) {
8571f0984d40SFabiano Rosas             gen_exception_insn_el(s, 0, EXCP_NOCP,
8572f0984d40SFabiano Rosas                                   syn_uncategorized(), s->fp_excp_el);
8573f0984d40SFabiano Rosas             return true;
8574f0984d40SFabiano Rosas         }
8575f0984d40SFabiano Rosas     }
8576f0984d40SFabiano Rosas 
8577f0984d40SFabiano Rosas     nextlabel = gen_disas_label(s);
8578f0984d40SFabiano Rosas     tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_R[a->rn], 0, nextlabel.label);
8579f0984d40SFabiano Rosas     tmp = load_reg(s, a->rn);
8580f0984d40SFabiano Rosas     store_reg(s, 14, tmp);
8581f0984d40SFabiano Rosas     if (a->size != 4) {
8582f0984d40SFabiano Rosas         /*
8583f0984d40SFabiano Rosas          * WLSTP: set FPSCR.LTPSIZE. This requires that we do the
8584f0984d40SFabiano Rosas          * lazy state preservation, new FP context creation, etc,
8585f0984d40SFabiano Rosas          * that vfp_access_check() does. We know that the actual
8586f0984d40SFabiano Rosas          * access check will succeed (ie it won't generate code that
8587f0984d40SFabiano Rosas          * throws an exception) because we did that check by hand earlier.
8588f0984d40SFabiano Rosas          */
8589f0984d40SFabiano Rosas         bool ok = vfp_access_check(s);
8590f0984d40SFabiano Rosas         assert(ok);
8591f0984d40SFabiano Rosas         store_cpu_field(tcg_constant_i32(a->size), v7m.ltpsize);
8592f0984d40SFabiano Rosas         /*
8593f0984d40SFabiano Rosas          * LTPSIZE updated, but MVE_NO_PRED will always be the same thing (0)
8594f0984d40SFabiano Rosas          * when we take this upcoming exit from this TB, so gen_jmp_tb() is OK.
8595f0984d40SFabiano Rosas          */
8596f0984d40SFabiano Rosas     }
8597f0984d40SFabiano Rosas     gen_jmp_tb(s, curr_insn_len(s), 1);
8598f0984d40SFabiano Rosas 
8599f0984d40SFabiano Rosas     set_disas_label(s, nextlabel);
8600f0984d40SFabiano Rosas     gen_jmp(s, jmp_diff(s, a->imm));
8601f0984d40SFabiano Rosas     return true;
8602f0984d40SFabiano Rosas }
8603f0984d40SFabiano Rosas 
8604f0984d40SFabiano Rosas static bool trans_LE(DisasContext *s, arg_LE *a)
8605f0984d40SFabiano Rosas {
8606f0984d40SFabiano Rosas     /*
8607f0984d40SFabiano Rosas      * M-profile low-overhead loop end. The architecture permits an
8608f0984d40SFabiano Rosas      * implementation to discard the LO_BRANCH_INFO cache at any time,
8609f0984d40SFabiano Rosas      * and we take the IMPDEF option to never set it in the first place
8610f0984d40SFabiano Rosas      * (equivalent to always discarding it immediately), because for QEMU
8611f0984d40SFabiano Rosas      * a "real" implementation would be complicated and wouldn't execute
8612f0984d40SFabiano Rosas      * any faster.
8613f0984d40SFabiano Rosas      */
8614f0984d40SFabiano Rosas     TCGv_i32 tmp;
8615f0984d40SFabiano Rosas     DisasLabel loopend;
8616f0984d40SFabiano Rosas     bool fpu_active;
8617f0984d40SFabiano Rosas 
8618f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_lob, s)) {
8619f0984d40SFabiano Rosas         return false;
8620f0984d40SFabiano Rosas     }
8621f0984d40SFabiano Rosas     if (a->f && a->tp) {
8622f0984d40SFabiano Rosas         return false;
8623f0984d40SFabiano Rosas     }
8624f0984d40SFabiano Rosas     if (s->condexec_mask) {
8625f0984d40SFabiano Rosas         /*
8626f0984d40SFabiano Rosas          * LE in an IT block is CONSTRAINED UNPREDICTABLE;
8627f0984d40SFabiano Rosas          * we choose to UNDEF, because otherwise our use of
8628f0984d40SFabiano Rosas          * gen_goto_tb(1) would clash with the use of TB exit 1
8629f0984d40SFabiano Rosas          * in the dc->condjmp condition-failed codepath in
8630f0984d40SFabiano Rosas          * arm_tr_tb_stop() and we'd get an assertion.
8631f0984d40SFabiano Rosas          */
8632f0984d40SFabiano Rosas         return false;
8633f0984d40SFabiano Rosas     }
8634f0984d40SFabiano Rosas     if (a->tp) {
8635f0984d40SFabiano Rosas         /* LETP */
8636f0984d40SFabiano Rosas         if (!dc_isar_feature(aa32_mve, s)) {
8637f0984d40SFabiano Rosas             return false;
8638f0984d40SFabiano Rosas         }
8639f0984d40SFabiano Rosas         if (!vfp_access_check(s)) {
8640f0984d40SFabiano Rosas             s->eci_handled = true;
8641f0984d40SFabiano Rosas             return true;
8642f0984d40SFabiano Rosas         }
8643f0984d40SFabiano Rosas     }
8644f0984d40SFabiano Rosas 
8645f0984d40SFabiano Rosas     /* LE/LETP is OK with ECI set and leaves it untouched */
8646f0984d40SFabiano Rosas     s->eci_handled = true;
8647f0984d40SFabiano Rosas 
8648f0984d40SFabiano Rosas     /*
8649f0984d40SFabiano Rosas      * With MVE, LTPSIZE might not be 4, and we must emit an INVSTATE
8650f0984d40SFabiano Rosas      * UsageFault exception for the LE insn in that case. Note that we
8651f0984d40SFabiano Rosas      * are not directly checking FPSCR.LTPSIZE but instead check the
8652f0984d40SFabiano Rosas      * pseudocode LTPSIZE() function, which returns 4 if the FPU is
8653f0984d40SFabiano Rosas      * not currently active (ie ActiveFPState() returns false). We
8654f0984d40SFabiano Rosas      * can identify not-active purely from our TB state flags, as the
8655f0984d40SFabiano Rosas      * FPU is active only if:
8656f0984d40SFabiano Rosas      *  the FPU is enabled
8657f0984d40SFabiano Rosas      *  AND lazy state preservation is not active
8658f0984d40SFabiano Rosas      *  AND we do not need a new fp context (this is the ASPEN/FPCA check)
8659f0984d40SFabiano Rosas      *
8660f0984d40SFabiano Rosas      * Usually we don't need to care about this distinction between
8661f0984d40SFabiano Rosas      * LTPSIZE and FPSCR.LTPSIZE, because the code in vfp_access_check()
8662f0984d40SFabiano Rosas      * will either take an exception or clear the conditions that make
8663f0984d40SFabiano Rosas      * the FPU not active. But LE is an unusual case of a non-FP insn
8664f0984d40SFabiano Rosas      * that looks at LTPSIZE.
8665f0984d40SFabiano Rosas      */
8666f0984d40SFabiano Rosas     fpu_active = !s->fp_excp_el && !s->v7m_lspact && !s->v7m_new_fp_ctxt_needed;
8667f0984d40SFabiano Rosas 
8668f0984d40SFabiano Rosas     if (!a->tp && dc_isar_feature(aa32_mve, s) && fpu_active) {
8669f0984d40SFabiano Rosas         /* Need to do a runtime check for LTPSIZE != 4 */
8670f0984d40SFabiano Rosas         DisasLabel skipexc = gen_disas_label(s);
8671f0984d40SFabiano Rosas         tmp = load_cpu_field(v7m.ltpsize);
8672f0984d40SFabiano Rosas         tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 4, skipexc.label);
8673f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
8674f0984d40SFabiano Rosas         gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized());
8675f0984d40SFabiano Rosas         set_disas_label(s, skipexc);
8676f0984d40SFabiano Rosas     }
8677f0984d40SFabiano Rosas 
8678f0984d40SFabiano Rosas     if (a->f) {
8679f0984d40SFabiano Rosas         /* Loop-forever: just jump back to the loop start */
8680f0984d40SFabiano Rosas         gen_jmp(s, jmp_diff(s, -a->imm));
8681f0984d40SFabiano Rosas         return true;
8682f0984d40SFabiano Rosas     }
8683f0984d40SFabiano Rosas 
8684f0984d40SFabiano Rosas     /*
8685f0984d40SFabiano Rosas      * Not loop-forever. If LR <= loop-decrement-value this is the last loop.
8686f0984d40SFabiano Rosas      * For LE, we know at this point that LTPSIZE must be 4 and the
8687f0984d40SFabiano Rosas      * loop decrement value is 1. For LETP we need to calculate the decrement
8688f0984d40SFabiano Rosas      * value from LTPSIZE.
8689f0984d40SFabiano Rosas      */
8690f0984d40SFabiano Rosas     loopend = gen_disas_label(s);
8691f0984d40SFabiano Rosas     if (!a->tp) {
8692f0984d40SFabiano Rosas         tcg_gen_brcondi_i32(TCG_COND_LEU, cpu_R[14], 1, loopend.label);
8693f0984d40SFabiano Rosas         tcg_gen_addi_i32(cpu_R[14], cpu_R[14], -1);
8694f0984d40SFabiano Rosas     } else {
8695f0984d40SFabiano Rosas         /*
8696f0984d40SFabiano Rosas          * Decrement by 1 << (4 - LTPSIZE). We need to use a TCG local
8697f0984d40SFabiano Rosas          * so that decr stays live after the brcondi.
8698f0984d40SFabiano Rosas          */
8699f0984d40SFabiano Rosas         TCGv_i32 decr = tcg_temp_local_new_i32();
8700f0984d40SFabiano Rosas         TCGv_i32 ltpsize = load_cpu_field(v7m.ltpsize);
8701f0984d40SFabiano Rosas         tcg_gen_sub_i32(decr, tcg_constant_i32(4), ltpsize);
8702f0984d40SFabiano Rosas         tcg_gen_shl_i32(decr, tcg_constant_i32(1), decr);
8703f0984d40SFabiano Rosas         tcg_temp_free_i32(ltpsize);
8704f0984d40SFabiano Rosas 
8705f0984d40SFabiano Rosas         tcg_gen_brcond_i32(TCG_COND_LEU, cpu_R[14], decr, loopend.label);
8706f0984d40SFabiano Rosas 
8707f0984d40SFabiano Rosas         tcg_gen_sub_i32(cpu_R[14], cpu_R[14], decr);
8708f0984d40SFabiano Rosas         tcg_temp_free_i32(decr);
8709f0984d40SFabiano Rosas     }
8710f0984d40SFabiano Rosas     /* Jump back to the loop start */
8711f0984d40SFabiano Rosas     gen_jmp(s, jmp_diff(s, -a->imm));
8712f0984d40SFabiano Rosas 
8713f0984d40SFabiano Rosas     set_disas_label(s, loopend);
8714f0984d40SFabiano Rosas     if (a->tp) {
8715f0984d40SFabiano Rosas         /* Exits from tail-pred loops must reset LTPSIZE to 4 */
8716f0984d40SFabiano Rosas         store_cpu_field(tcg_constant_i32(4), v7m.ltpsize);
8717f0984d40SFabiano Rosas     }
8718f0984d40SFabiano Rosas     /* End TB, continuing to following insn */
8719f0984d40SFabiano Rosas     gen_jmp_tb(s, curr_insn_len(s), 1);
8720f0984d40SFabiano Rosas     return true;
8721f0984d40SFabiano Rosas }
8722f0984d40SFabiano Rosas 
8723f0984d40SFabiano Rosas static bool trans_LCTP(DisasContext *s, arg_LCTP *a)
8724f0984d40SFabiano Rosas {
8725f0984d40SFabiano Rosas     /*
8726f0984d40SFabiano Rosas      * M-profile Loop Clear with Tail Predication. Since our implementation
8727f0984d40SFabiano Rosas      * doesn't cache branch information, all we need to do is reset
8728f0984d40SFabiano Rosas      * FPSCR.LTPSIZE to 4.
8729f0984d40SFabiano Rosas      */
8730f0984d40SFabiano Rosas 
8731f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_lob, s) ||
8732f0984d40SFabiano Rosas         !dc_isar_feature(aa32_mve, s)) {
8733f0984d40SFabiano Rosas         return false;
8734f0984d40SFabiano Rosas     }
8735f0984d40SFabiano Rosas 
8736f0984d40SFabiano Rosas     if (!vfp_access_check(s)) {
8737f0984d40SFabiano Rosas         return true;
8738f0984d40SFabiano Rosas     }
8739f0984d40SFabiano Rosas 
8740f0984d40SFabiano Rosas     store_cpu_field_constant(4, v7m.ltpsize);
8741f0984d40SFabiano Rosas     return true;
8742f0984d40SFabiano Rosas }
8743f0984d40SFabiano Rosas 
8744f0984d40SFabiano Rosas static bool trans_VCTP(DisasContext *s, arg_VCTP *a)
8745f0984d40SFabiano Rosas {
8746f0984d40SFabiano Rosas     /*
8747f0984d40SFabiano Rosas      * M-profile Create Vector Tail Predicate. This insn is itself
8748f0984d40SFabiano Rosas      * predicated and is subject to beatwise execution.
8749f0984d40SFabiano Rosas      */
8750f0984d40SFabiano Rosas     TCGv_i32 rn_shifted, masklen;
8751f0984d40SFabiano Rosas 
8752f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_mve, s) || a->rn == 13 || a->rn == 15) {
8753f0984d40SFabiano Rosas         return false;
8754f0984d40SFabiano Rosas     }
8755f0984d40SFabiano Rosas 
8756f0984d40SFabiano Rosas     if (!mve_eci_check(s) || !vfp_access_check(s)) {
8757f0984d40SFabiano Rosas         return true;
8758f0984d40SFabiano Rosas     }
8759f0984d40SFabiano Rosas 
8760f0984d40SFabiano Rosas     /*
8761f0984d40SFabiano Rosas      * We pre-calculate the mask length here to avoid having
8762f0984d40SFabiano Rosas      * to have multiple helpers specialized for size.
8763f0984d40SFabiano Rosas      * We pass the helper "rn <= (1 << (4 - size)) ? (rn << size) : 16".
8764f0984d40SFabiano Rosas      */
8765f0984d40SFabiano Rosas     rn_shifted = tcg_temp_new_i32();
8766f0984d40SFabiano Rosas     masklen = load_reg(s, a->rn);
8767f0984d40SFabiano Rosas     tcg_gen_shli_i32(rn_shifted, masklen, a->size);
8768f0984d40SFabiano Rosas     tcg_gen_movcond_i32(TCG_COND_LEU, masklen,
8769f0984d40SFabiano Rosas                         masklen, tcg_constant_i32(1 << (4 - a->size)),
8770f0984d40SFabiano Rosas                         rn_shifted, tcg_constant_i32(16));
8771f0984d40SFabiano Rosas     gen_helper_mve_vctp(cpu_env, masklen);
8772f0984d40SFabiano Rosas     tcg_temp_free_i32(masklen);
8773f0984d40SFabiano Rosas     tcg_temp_free_i32(rn_shifted);
8774f0984d40SFabiano Rosas     /* This insn updates predication bits */
8775f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
8776f0984d40SFabiano Rosas     mve_update_eci(s);
8777f0984d40SFabiano Rosas     return true;
8778f0984d40SFabiano Rosas }
8779f0984d40SFabiano Rosas 
8780f0984d40SFabiano Rosas static bool op_tbranch(DisasContext *s, arg_tbranch *a, bool half)
8781f0984d40SFabiano Rosas {
8782f0984d40SFabiano Rosas     TCGv_i32 addr, tmp;
8783f0984d40SFabiano Rosas 
8784f0984d40SFabiano Rosas     tmp = load_reg(s, a->rm);
8785f0984d40SFabiano Rosas     if (half) {
8786f0984d40SFabiano Rosas         tcg_gen_add_i32(tmp, tmp, tmp);
8787f0984d40SFabiano Rosas     }
8788f0984d40SFabiano Rosas     addr = load_reg(s, a->rn);
8789f0984d40SFabiano Rosas     tcg_gen_add_i32(addr, addr, tmp);
8790f0984d40SFabiano Rosas 
8791f0984d40SFabiano Rosas     gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), half ? MO_UW : MO_UB);
8792f0984d40SFabiano Rosas 
8793f0984d40SFabiano Rosas     tcg_gen_add_i32(tmp, tmp, tmp);
8794f0984d40SFabiano Rosas     gen_pc_plus_diff(s, addr, jmp_diff(s, 0));
8795f0984d40SFabiano Rosas     tcg_gen_add_i32(tmp, tmp, addr);
8796f0984d40SFabiano Rosas     tcg_temp_free_i32(addr);
8797f0984d40SFabiano Rosas     store_reg(s, 15, tmp);
8798f0984d40SFabiano Rosas     return true;
8799f0984d40SFabiano Rosas }
8800f0984d40SFabiano Rosas 
8801f0984d40SFabiano Rosas static bool trans_TBB(DisasContext *s, arg_tbranch *a)
8802f0984d40SFabiano Rosas {
8803f0984d40SFabiano Rosas     return op_tbranch(s, a, false);
8804f0984d40SFabiano Rosas }
8805f0984d40SFabiano Rosas 
8806f0984d40SFabiano Rosas static bool trans_TBH(DisasContext *s, arg_tbranch *a)
8807f0984d40SFabiano Rosas {
8808f0984d40SFabiano Rosas     return op_tbranch(s, a, true);
8809f0984d40SFabiano Rosas }
8810f0984d40SFabiano Rosas 
8811f0984d40SFabiano Rosas static bool trans_CBZ(DisasContext *s, arg_CBZ *a)
8812f0984d40SFabiano Rosas {
8813f0984d40SFabiano Rosas     TCGv_i32 tmp = load_reg(s, a->rn);
8814f0984d40SFabiano Rosas 
8815f0984d40SFabiano Rosas     arm_gen_condlabel(s);
8816f0984d40SFabiano Rosas     tcg_gen_brcondi_i32(a->nz ? TCG_COND_EQ : TCG_COND_NE,
8817f0984d40SFabiano Rosas                         tmp, 0, s->condlabel.label);
8818f0984d40SFabiano Rosas     tcg_temp_free_i32(tmp);
8819f0984d40SFabiano Rosas     gen_jmp(s, jmp_diff(s, a->imm));
8820f0984d40SFabiano Rosas     return true;
8821f0984d40SFabiano Rosas }
8822f0984d40SFabiano Rosas 
8823f0984d40SFabiano Rosas /*
8824f0984d40SFabiano Rosas  * Supervisor call - both T32 & A32 come here so we need to check
8825f0984d40SFabiano Rosas  * which mode we are in when checking for semihosting.
8826f0984d40SFabiano Rosas  */
8827f0984d40SFabiano Rosas 
8828f0984d40SFabiano Rosas static bool trans_SVC(DisasContext *s, arg_SVC *a)
8829f0984d40SFabiano Rosas {
8830f0984d40SFabiano Rosas     const uint32_t semihost_imm = s->thumb ? 0xab : 0x123456;
8831f0984d40SFabiano Rosas 
8832f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_M) &&
8833f0984d40SFabiano Rosas         semihosting_enabled(s->current_el == 0) &&
8834f0984d40SFabiano Rosas         (a->imm == semihost_imm)) {
8835f0984d40SFabiano Rosas         gen_exception_internal_insn(s, EXCP_SEMIHOST);
8836f0984d40SFabiano Rosas     } else {
8837f0984d40SFabiano Rosas         if (s->fgt_svc) {
8838f0984d40SFabiano Rosas             uint32_t syndrome = syn_aa32_svc(a->imm, s->thumb);
8839f0984d40SFabiano Rosas             gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2);
8840f0984d40SFabiano Rosas         } else {
8841f0984d40SFabiano Rosas             gen_update_pc(s, curr_insn_len(s));
8842f0984d40SFabiano Rosas             s->svc_imm = a->imm;
8843f0984d40SFabiano Rosas             s->base.is_jmp = DISAS_SWI;
8844f0984d40SFabiano Rosas         }
8845f0984d40SFabiano Rosas     }
8846f0984d40SFabiano Rosas     return true;
8847f0984d40SFabiano Rosas }
8848f0984d40SFabiano Rosas 
8849f0984d40SFabiano Rosas /*
8850f0984d40SFabiano Rosas  * Unconditional system instructions
8851f0984d40SFabiano Rosas  */
8852f0984d40SFabiano Rosas 
8853f0984d40SFabiano Rosas static bool trans_RFE(DisasContext *s, arg_RFE *a)
8854f0984d40SFabiano Rosas {
8855f0984d40SFabiano Rosas     static const int8_t pre_offset[4] = {
8856f0984d40SFabiano Rosas         /* DA */ -4, /* IA */ 0, /* DB */ -8, /* IB */ 4
8857f0984d40SFabiano Rosas     };
8858f0984d40SFabiano Rosas     static const int8_t post_offset[4] = {
8859f0984d40SFabiano Rosas         /* DA */ -8, /* IA */ 4, /* DB */ -4, /* IB */ 0
8860f0984d40SFabiano Rosas     };
8861f0984d40SFabiano Rosas     TCGv_i32 addr, t1, t2;
8862f0984d40SFabiano Rosas 
8863f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) {
8864f0984d40SFabiano Rosas         return false;
8865f0984d40SFabiano Rosas     }
8866f0984d40SFabiano Rosas     if (IS_USER(s)) {
8867f0984d40SFabiano Rosas         unallocated_encoding(s);
8868f0984d40SFabiano Rosas         return true;
8869f0984d40SFabiano Rosas     }
8870f0984d40SFabiano Rosas 
8871f0984d40SFabiano Rosas     addr = load_reg(s, a->rn);
8872f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, pre_offset[a->pu]);
8873f0984d40SFabiano Rosas 
8874f0984d40SFabiano Rosas     /* Load PC into tmp and CPSR into tmp2.  */
8875f0984d40SFabiano Rosas     t1 = tcg_temp_new_i32();
8876f0984d40SFabiano Rosas     gen_aa32_ld_i32(s, t1, addr, get_mem_index(s), MO_UL | MO_ALIGN);
8877f0984d40SFabiano Rosas     tcg_gen_addi_i32(addr, addr, 4);
8878f0984d40SFabiano Rosas     t2 = tcg_temp_new_i32();
8879f0984d40SFabiano Rosas     gen_aa32_ld_i32(s, t2, addr, get_mem_index(s), MO_UL | MO_ALIGN);
8880f0984d40SFabiano Rosas 
8881f0984d40SFabiano Rosas     if (a->w) {
8882f0984d40SFabiano Rosas         /* Base writeback.  */
8883f0984d40SFabiano Rosas         tcg_gen_addi_i32(addr, addr, post_offset[a->pu]);
8884f0984d40SFabiano Rosas         store_reg(s, a->rn, addr);
8885f0984d40SFabiano Rosas     } else {
8886f0984d40SFabiano Rosas         tcg_temp_free_i32(addr);
8887f0984d40SFabiano Rosas     }
8888f0984d40SFabiano Rosas     gen_rfe(s, t1, t2);
8889f0984d40SFabiano Rosas     return true;
8890f0984d40SFabiano Rosas }
8891f0984d40SFabiano Rosas 
8892f0984d40SFabiano Rosas static bool trans_SRS(DisasContext *s, arg_SRS *a)
8893f0984d40SFabiano Rosas {
8894f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) {
8895f0984d40SFabiano Rosas         return false;
8896f0984d40SFabiano Rosas     }
8897f0984d40SFabiano Rosas     gen_srs(s, a->mode, a->pu, a->w);
8898f0984d40SFabiano Rosas     return true;
8899f0984d40SFabiano Rosas }
8900f0984d40SFabiano Rosas 
8901f0984d40SFabiano Rosas static bool trans_CPS(DisasContext *s, arg_CPS *a)
8902f0984d40SFabiano Rosas {
8903f0984d40SFabiano Rosas     uint32_t mask, val;
8904f0984d40SFabiano Rosas 
8905f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) {
8906f0984d40SFabiano Rosas         return false;
8907f0984d40SFabiano Rosas     }
8908f0984d40SFabiano Rosas     if (IS_USER(s)) {
8909f0984d40SFabiano Rosas         /* Implemented as NOP in user mode.  */
8910f0984d40SFabiano Rosas         return true;
8911f0984d40SFabiano Rosas     }
8912f0984d40SFabiano Rosas     /* TODO: There are quite a lot of UNPREDICTABLE argument combinations. */
8913f0984d40SFabiano Rosas 
8914f0984d40SFabiano Rosas     mask = val = 0;
8915f0984d40SFabiano Rosas     if (a->imod & 2) {
8916f0984d40SFabiano Rosas         if (a->A) {
8917f0984d40SFabiano Rosas             mask |= CPSR_A;
8918f0984d40SFabiano Rosas         }
8919f0984d40SFabiano Rosas         if (a->I) {
8920f0984d40SFabiano Rosas             mask |= CPSR_I;
8921f0984d40SFabiano Rosas         }
8922f0984d40SFabiano Rosas         if (a->F) {
8923f0984d40SFabiano Rosas             mask |= CPSR_F;
8924f0984d40SFabiano Rosas         }
8925f0984d40SFabiano Rosas         if (a->imod & 1) {
8926f0984d40SFabiano Rosas             val |= mask;
8927f0984d40SFabiano Rosas         }
8928f0984d40SFabiano Rosas     }
8929f0984d40SFabiano Rosas     if (a->M) {
8930f0984d40SFabiano Rosas         mask |= CPSR_M;
8931f0984d40SFabiano Rosas         val |= a->mode;
8932f0984d40SFabiano Rosas     }
8933f0984d40SFabiano Rosas     if (mask) {
8934f0984d40SFabiano Rosas         gen_set_psr_im(s, mask, 0, val);
8935f0984d40SFabiano Rosas     }
8936f0984d40SFabiano Rosas     return true;
8937f0984d40SFabiano Rosas }
8938f0984d40SFabiano Rosas 
8939f0984d40SFabiano Rosas static bool trans_CPS_v7m(DisasContext *s, arg_CPS_v7m *a)
8940f0984d40SFabiano Rosas {
8941f0984d40SFabiano Rosas     TCGv_i32 tmp, addr;
8942f0984d40SFabiano Rosas 
8943f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_M)) {
8944f0984d40SFabiano Rosas         return false;
8945f0984d40SFabiano Rosas     }
8946f0984d40SFabiano Rosas     if (IS_USER(s)) {
8947f0984d40SFabiano Rosas         /* Implemented as NOP in user mode.  */
8948f0984d40SFabiano Rosas         return true;
8949f0984d40SFabiano Rosas     }
8950f0984d40SFabiano Rosas 
8951f0984d40SFabiano Rosas     tmp = tcg_constant_i32(a->im);
8952f0984d40SFabiano Rosas     /* FAULTMASK */
8953f0984d40SFabiano Rosas     if (a->F) {
8954f0984d40SFabiano Rosas         addr = tcg_constant_i32(19);
8955f0984d40SFabiano Rosas         gen_helper_v7m_msr(cpu_env, addr, tmp);
8956f0984d40SFabiano Rosas     }
8957f0984d40SFabiano Rosas     /* PRIMASK */
8958f0984d40SFabiano Rosas     if (a->I) {
8959f0984d40SFabiano Rosas         addr = tcg_constant_i32(16);
8960f0984d40SFabiano Rosas         gen_helper_v7m_msr(cpu_env, addr, tmp);
8961f0984d40SFabiano Rosas     }
8962f0984d40SFabiano Rosas     gen_rebuild_hflags(s, false);
8963f0984d40SFabiano Rosas     gen_lookup_tb(s);
8964f0984d40SFabiano Rosas     return true;
8965f0984d40SFabiano Rosas }
8966f0984d40SFabiano Rosas 
8967f0984d40SFabiano Rosas /*
8968f0984d40SFabiano Rosas  * Clear-Exclusive, Barriers
8969f0984d40SFabiano Rosas  */
8970f0984d40SFabiano Rosas 
8971f0984d40SFabiano Rosas static bool trans_CLREX(DisasContext *s, arg_CLREX *a)
8972f0984d40SFabiano Rosas {
8973f0984d40SFabiano Rosas     if (s->thumb
8974f0984d40SFabiano Rosas         ? !ENABLE_ARCH_7 && !arm_dc_feature(s, ARM_FEATURE_M)
8975f0984d40SFabiano Rosas         : !ENABLE_ARCH_6K) {
8976f0984d40SFabiano Rosas         return false;
8977f0984d40SFabiano Rosas     }
8978f0984d40SFabiano Rosas     gen_clrex(s);
8979f0984d40SFabiano Rosas     return true;
8980f0984d40SFabiano Rosas }
8981f0984d40SFabiano Rosas 
8982f0984d40SFabiano Rosas static bool trans_DSB(DisasContext *s, arg_DSB *a)
8983f0984d40SFabiano Rosas {
8984f0984d40SFabiano Rosas     if (!ENABLE_ARCH_7 && !arm_dc_feature(s, ARM_FEATURE_M)) {
8985f0984d40SFabiano Rosas         return false;
8986f0984d40SFabiano Rosas     }
8987f0984d40SFabiano Rosas     tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
8988f0984d40SFabiano Rosas     return true;
8989f0984d40SFabiano Rosas }
8990f0984d40SFabiano Rosas 
8991f0984d40SFabiano Rosas static bool trans_DMB(DisasContext *s, arg_DMB *a)
8992f0984d40SFabiano Rosas {
8993f0984d40SFabiano Rosas     return trans_DSB(s, NULL);
8994f0984d40SFabiano Rosas }
8995f0984d40SFabiano Rosas 
8996f0984d40SFabiano Rosas static bool trans_ISB(DisasContext *s, arg_ISB *a)
8997f0984d40SFabiano Rosas {
8998f0984d40SFabiano Rosas     if (!ENABLE_ARCH_7 && !arm_dc_feature(s, ARM_FEATURE_M)) {
8999f0984d40SFabiano Rosas         return false;
9000f0984d40SFabiano Rosas     }
9001f0984d40SFabiano Rosas     /*
9002f0984d40SFabiano Rosas      * We need to break the TB after this insn to execute
9003f0984d40SFabiano Rosas      * self-modifying code correctly and also to take
9004f0984d40SFabiano Rosas      * any pending interrupts immediately.
9005f0984d40SFabiano Rosas      */
9006f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_TOO_MANY;
9007f0984d40SFabiano Rosas     return true;
9008f0984d40SFabiano Rosas }
9009f0984d40SFabiano Rosas 
9010f0984d40SFabiano Rosas static bool trans_SB(DisasContext *s, arg_SB *a)
9011f0984d40SFabiano Rosas {
9012f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_sb, s)) {
9013f0984d40SFabiano Rosas         return false;
9014f0984d40SFabiano Rosas     }
9015f0984d40SFabiano Rosas     /*
9016f0984d40SFabiano Rosas      * TODO: There is no speculation barrier opcode
9017f0984d40SFabiano Rosas      * for TCG; MB and end the TB instead.
9018f0984d40SFabiano Rosas      */
9019f0984d40SFabiano Rosas     tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
9020f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_TOO_MANY;
9021f0984d40SFabiano Rosas     return true;
9022f0984d40SFabiano Rosas }
9023f0984d40SFabiano Rosas 
9024f0984d40SFabiano Rosas static bool trans_SETEND(DisasContext *s, arg_SETEND *a)
9025f0984d40SFabiano Rosas {
9026f0984d40SFabiano Rosas     if (!ENABLE_ARCH_6) {
9027f0984d40SFabiano Rosas         return false;
9028f0984d40SFabiano Rosas     }
9029f0984d40SFabiano Rosas     if (a->E != (s->be_data == MO_BE)) {
9030f0984d40SFabiano Rosas         gen_helper_setend(cpu_env);
9031f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_UPDATE_EXIT;
9032f0984d40SFabiano Rosas     }
9033f0984d40SFabiano Rosas     return true;
9034f0984d40SFabiano Rosas }
9035f0984d40SFabiano Rosas 
9036f0984d40SFabiano Rosas /*
9037f0984d40SFabiano Rosas  * Preload instructions
9038f0984d40SFabiano Rosas  * All are nops, contingent on the appropriate arch level.
9039f0984d40SFabiano Rosas  */
9040f0984d40SFabiano Rosas 
9041f0984d40SFabiano Rosas static bool trans_PLD(DisasContext *s, arg_PLD *a)
9042f0984d40SFabiano Rosas {
9043f0984d40SFabiano Rosas     return ENABLE_ARCH_5TE;
9044f0984d40SFabiano Rosas }
9045f0984d40SFabiano Rosas 
9046f0984d40SFabiano Rosas static bool trans_PLDW(DisasContext *s, arg_PLD *a)
9047f0984d40SFabiano Rosas {
9048f0984d40SFabiano Rosas     return arm_dc_feature(s, ARM_FEATURE_V7MP);
9049f0984d40SFabiano Rosas }
9050f0984d40SFabiano Rosas 
9051f0984d40SFabiano Rosas static bool trans_PLI(DisasContext *s, arg_PLD *a)
9052f0984d40SFabiano Rosas {
9053f0984d40SFabiano Rosas     return ENABLE_ARCH_7;
9054f0984d40SFabiano Rosas }
9055f0984d40SFabiano Rosas 
9056f0984d40SFabiano Rosas /*
9057f0984d40SFabiano Rosas  * If-then
9058f0984d40SFabiano Rosas  */
9059f0984d40SFabiano Rosas 
9060f0984d40SFabiano Rosas static bool trans_IT(DisasContext *s, arg_IT *a)
9061f0984d40SFabiano Rosas {
9062f0984d40SFabiano Rosas     int cond_mask = a->cond_mask;
9063f0984d40SFabiano Rosas 
9064f0984d40SFabiano Rosas     /*
9065f0984d40SFabiano Rosas      * No actual code generated for this insn, just setup state.
9066f0984d40SFabiano Rosas      *
9067f0984d40SFabiano Rosas      * Combinations of firstcond and mask which set up an 0b1111
9068f0984d40SFabiano Rosas      * condition are UNPREDICTABLE; we take the CONSTRAINED
9069f0984d40SFabiano Rosas      * UNPREDICTABLE choice to treat 0b1111 the same as 0b1110,
9070f0984d40SFabiano Rosas      * i.e. both meaning "execute always".
9071f0984d40SFabiano Rosas      */
9072f0984d40SFabiano Rosas     s->condexec_cond = (cond_mask >> 4) & 0xe;
9073f0984d40SFabiano Rosas     s->condexec_mask = cond_mask & 0x1f;
9074f0984d40SFabiano Rosas     return true;
9075f0984d40SFabiano Rosas }
9076f0984d40SFabiano Rosas 
9077f0984d40SFabiano Rosas /* v8.1M CSEL/CSINC/CSNEG/CSINV */
9078f0984d40SFabiano Rosas static bool trans_CSEL(DisasContext *s, arg_CSEL *a)
9079f0984d40SFabiano Rosas {
9080f0984d40SFabiano Rosas     TCGv_i32 rn, rm, zero;
9081f0984d40SFabiano Rosas     DisasCompare c;
9082f0984d40SFabiano Rosas 
9083f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
9084f0984d40SFabiano Rosas         return false;
9085f0984d40SFabiano Rosas     }
9086f0984d40SFabiano Rosas 
9087f0984d40SFabiano Rosas     if (a->rm == 13) {
9088f0984d40SFabiano Rosas         /* SEE "Related encodings" (MVE shifts) */
9089f0984d40SFabiano Rosas         return false;
9090f0984d40SFabiano Rosas     }
9091f0984d40SFabiano Rosas 
9092f0984d40SFabiano Rosas     if (a->rd == 13 || a->rd == 15 || a->rn == 13 || a->fcond >= 14) {
9093f0984d40SFabiano Rosas         /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
9094f0984d40SFabiano Rosas         return false;
9095f0984d40SFabiano Rosas     }
9096f0984d40SFabiano Rosas 
9097f0984d40SFabiano Rosas     /* In this insn input reg fields of 0b1111 mean "zero", not "PC" */
9098f0984d40SFabiano Rosas     zero = tcg_constant_i32(0);
9099f0984d40SFabiano Rosas     if (a->rn == 15) {
9100f0984d40SFabiano Rosas         rn = zero;
9101f0984d40SFabiano Rosas     } else {
9102f0984d40SFabiano Rosas         rn = load_reg(s, a->rn);
9103f0984d40SFabiano Rosas     }
9104f0984d40SFabiano Rosas     if (a->rm == 15) {
9105f0984d40SFabiano Rosas         rm = zero;
9106f0984d40SFabiano Rosas     } else {
9107f0984d40SFabiano Rosas         rm = load_reg(s, a->rm);
9108f0984d40SFabiano Rosas     }
9109f0984d40SFabiano Rosas 
9110f0984d40SFabiano Rosas     switch (a->op) {
9111f0984d40SFabiano Rosas     case 0: /* CSEL */
9112f0984d40SFabiano Rosas         break;
9113f0984d40SFabiano Rosas     case 1: /* CSINC */
9114f0984d40SFabiano Rosas         tcg_gen_addi_i32(rm, rm, 1);
9115f0984d40SFabiano Rosas         break;
9116f0984d40SFabiano Rosas     case 2: /* CSINV */
9117f0984d40SFabiano Rosas         tcg_gen_not_i32(rm, rm);
9118f0984d40SFabiano Rosas         break;
9119f0984d40SFabiano Rosas     case 3: /* CSNEG */
9120f0984d40SFabiano Rosas         tcg_gen_neg_i32(rm, rm);
9121f0984d40SFabiano Rosas         break;
9122f0984d40SFabiano Rosas     default:
9123f0984d40SFabiano Rosas         g_assert_not_reached();
9124f0984d40SFabiano Rosas     }
9125f0984d40SFabiano Rosas 
9126f0984d40SFabiano Rosas     arm_test_cc(&c, a->fcond);
9127f0984d40SFabiano Rosas     tcg_gen_movcond_i32(c.cond, rn, c.value, zero, rn, rm);
9128f0984d40SFabiano Rosas     arm_free_cc(&c);
9129f0984d40SFabiano Rosas 
9130f0984d40SFabiano Rosas     store_reg(s, a->rd, rn);
9131f0984d40SFabiano Rosas     tcg_temp_free_i32(rm);
9132f0984d40SFabiano Rosas 
9133f0984d40SFabiano Rosas     return true;
9134f0984d40SFabiano Rosas }
9135f0984d40SFabiano Rosas 
9136f0984d40SFabiano Rosas /*
9137f0984d40SFabiano Rosas  * Legacy decoder.
9138f0984d40SFabiano Rosas  */
9139f0984d40SFabiano Rosas 
9140f0984d40SFabiano Rosas static void disas_arm_insn(DisasContext *s, unsigned int insn)
9141f0984d40SFabiano Rosas {
9142f0984d40SFabiano Rosas     unsigned int cond = insn >> 28;
9143f0984d40SFabiano Rosas 
9144f0984d40SFabiano Rosas     /* M variants do not implement ARM mode; this must raise the INVSTATE
9145f0984d40SFabiano Rosas      * UsageFault exception.
9146f0984d40SFabiano Rosas      */
9147f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M)) {
9148f0984d40SFabiano Rosas         gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized());
9149f0984d40SFabiano Rosas         return;
9150f0984d40SFabiano Rosas     }
9151f0984d40SFabiano Rosas 
9152f0984d40SFabiano Rosas     if (s->pstate_il) {
9153f0984d40SFabiano Rosas         /*
9154f0984d40SFabiano Rosas          * Illegal execution state. This has priority over BTI
9155f0984d40SFabiano Rosas          * exceptions, but comes after instruction abort exceptions.
9156f0984d40SFabiano Rosas          */
9157f0984d40SFabiano Rosas         gen_exception_insn(s, 0, EXCP_UDEF, syn_illegalstate());
9158f0984d40SFabiano Rosas         return;
9159f0984d40SFabiano Rosas     }
9160f0984d40SFabiano Rosas 
9161f0984d40SFabiano Rosas     if (cond == 0xf) {
9162f0984d40SFabiano Rosas         /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we
9163f0984d40SFabiano Rosas          * choose to UNDEF. In ARMv5 and above the space is used
9164f0984d40SFabiano Rosas          * for miscellaneous unconditional instructions.
9165f0984d40SFabiano Rosas          */
9166f0984d40SFabiano Rosas         if (!arm_dc_feature(s, ARM_FEATURE_V5)) {
9167f0984d40SFabiano Rosas             unallocated_encoding(s);
9168f0984d40SFabiano Rosas             return;
9169f0984d40SFabiano Rosas         }
9170f0984d40SFabiano Rosas 
9171f0984d40SFabiano Rosas         /* Unconditional instructions.  */
9172f0984d40SFabiano Rosas         /* TODO: Perhaps merge these into one decodetree output file.  */
9173f0984d40SFabiano Rosas         if (disas_a32_uncond(s, insn) ||
9174f0984d40SFabiano Rosas             disas_vfp_uncond(s, insn) ||
9175f0984d40SFabiano Rosas             disas_neon_dp(s, insn) ||
9176f0984d40SFabiano Rosas             disas_neon_ls(s, insn) ||
9177f0984d40SFabiano Rosas             disas_neon_shared(s, insn)) {
9178f0984d40SFabiano Rosas             return;
9179f0984d40SFabiano Rosas         }
9180f0984d40SFabiano Rosas         /* fall back to legacy decoder */
9181f0984d40SFabiano Rosas 
9182f0984d40SFabiano Rosas         if ((insn & 0x0e000f00) == 0x0c000100) {
9183f0984d40SFabiano Rosas             if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
9184f0984d40SFabiano Rosas                 /* iWMMXt register transfer.  */
9185f0984d40SFabiano Rosas                 if (extract32(s->c15_cpar, 1, 1)) {
9186f0984d40SFabiano Rosas                     if (!disas_iwmmxt_insn(s, insn)) {
9187f0984d40SFabiano Rosas                         return;
9188f0984d40SFabiano Rosas                     }
9189f0984d40SFabiano Rosas                 }
9190f0984d40SFabiano Rosas             }
9191f0984d40SFabiano Rosas         }
9192f0984d40SFabiano Rosas         goto illegal_op;
9193f0984d40SFabiano Rosas     }
9194f0984d40SFabiano Rosas     if (cond != 0xe) {
9195f0984d40SFabiano Rosas         /* if not always execute, we generate a conditional jump to
9196f0984d40SFabiano Rosas            next instruction */
9197f0984d40SFabiano Rosas         arm_skip_unless(s, cond);
9198f0984d40SFabiano Rosas     }
9199f0984d40SFabiano Rosas 
9200f0984d40SFabiano Rosas     /* TODO: Perhaps merge these into one decodetree output file.  */
9201f0984d40SFabiano Rosas     if (disas_a32(s, insn) ||
9202f0984d40SFabiano Rosas         disas_vfp(s, insn)) {
9203f0984d40SFabiano Rosas         return;
9204f0984d40SFabiano Rosas     }
9205f0984d40SFabiano Rosas     /* fall back to legacy decoder */
9206f0984d40SFabiano Rosas     /* TODO: convert xscale/iwmmxt decoder to decodetree ?? */
9207f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_XSCALE)) {
9208f0984d40SFabiano Rosas         if (((insn & 0x0c000e00) == 0x0c000000)
9209f0984d40SFabiano Rosas             && ((insn & 0x03000000) != 0x03000000)) {
9210f0984d40SFabiano Rosas             /* Coprocessor insn, coprocessor 0 or 1 */
9211f0984d40SFabiano Rosas             disas_xscale_insn(s, insn);
9212f0984d40SFabiano Rosas             return;
9213f0984d40SFabiano Rosas         }
9214f0984d40SFabiano Rosas     }
9215f0984d40SFabiano Rosas 
9216f0984d40SFabiano Rosas illegal_op:
9217f0984d40SFabiano Rosas     unallocated_encoding(s);
9218f0984d40SFabiano Rosas }
9219f0984d40SFabiano Rosas 
9220f0984d40SFabiano Rosas static bool thumb_insn_is_16bit(DisasContext *s, uint32_t pc, uint32_t insn)
9221f0984d40SFabiano Rosas {
9222f0984d40SFabiano Rosas     /*
9223f0984d40SFabiano Rosas      * Return true if this is a 16 bit instruction. We must be precise
9224f0984d40SFabiano Rosas      * about this (matching the decode).
9225f0984d40SFabiano Rosas      */
9226f0984d40SFabiano Rosas     if ((insn >> 11) < 0x1d) {
9227f0984d40SFabiano Rosas         /* Definitely a 16-bit instruction */
9228f0984d40SFabiano Rosas         return true;
9229f0984d40SFabiano Rosas     }
9230f0984d40SFabiano Rosas 
9231f0984d40SFabiano Rosas     /* Top five bits 0b11101 / 0b11110 / 0b11111 : this is the
9232f0984d40SFabiano Rosas      * first half of a 32-bit Thumb insn. Thumb-1 cores might
9233f0984d40SFabiano Rosas      * end up actually treating this as two 16-bit insns, though,
9234f0984d40SFabiano Rosas      * if it's half of a bl/blx pair that might span a page boundary.
9235f0984d40SFabiano Rosas      */
9236f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_THUMB2) ||
9237f0984d40SFabiano Rosas         arm_dc_feature(s, ARM_FEATURE_M)) {
9238f0984d40SFabiano Rosas         /* Thumb2 cores (including all M profile ones) always treat
9239f0984d40SFabiano Rosas          * 32-bit insns as 32-bit.
9240f0984d40SFabiano Rosas          */
9241f0984d40SFabiano Rosas         return false;
9242f0984d40SFabiano Rosas     }
9243f0984d40SFabiano Rosas 
9244f0984d40SFabiano Rosas     if ((insn >> 11) == 0x1e && pc - s->page_start < TARGET_PAGE_SIZE - 3) {
9245f0984d40SFabiano Rosas         /* 0b1111_0xxx_xxxx_xxxx : BL/BLX prefix, and the suffix
9246f0984d40SFabiano Rosas          * is not on the next page; we merge this into a 32-bit
9247f0984d40SFabiano Rosas          * insn.
9248f0984d40SFabiano Rosas          */
9249f0984d40SFabiano Rosas         return false;
9250f0984d40SFabiano Rosas     }
9251f0984d40SFabiano Rosas     /* 0b1110_1xxx_xxxx_xxxx : BLX suffix (or UNDEF);
9252f0984d40SFabiano Rosas      * 0b1111_1xxx_xxxx_xxxx : BL suffix;
9253f0984d40SFabiano Rosas      * 0b1111_0xxx_xxxx_xxxx : BL/BLX prefix on the end of a page
9254f0984d40SFabiano Rosas      *  -- handle as single 16 bit insn
9255f0984d40SFabiano Rosas      */
9256f0984d40SFabiano Rosas     return true;
9257f0984d40SFabiano Rosas }
9258f0984d40SFabiano Rosas 
9259f0984d40SFabiano Rosas /* Translate a 32-bit thumb instruction. */
9260f0984d40SFabiano Rosas static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
9261f0984d40SFabiano Rosas {
9262f0984d40SFabiano Rosas     /*
9263f0984d40SFabiano Rosas      * ARMv6-M supports a limited subset of Thumb2 instructions.
9264f0984d40SFabiano Rosas      * Other Thumb1 architectures allow only 32-bit
9265f0984d40SFabiano Rosas      * combined BL/BLX prefix and suffix.
9266f0984d40SFabiano Rosas      */
9267f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M) &&
9268f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_V7)) {
9269f0984d40SFabiano Rosas         int i;
9270f0984d40SFabiano Rosas         bool found = false;
9271f0984d40SFabiano Rosas         static const uint32_t armv6m_insn[] = {0xf3808000 /* msr */,
9272f0984d40SFabiano Rosas                                                0xf3b08040 /* dsb */,
9273f0984d40SFabiano Rosas                                                0xf3b08050 /* dmb */,
9274f0984d40SFabiano Rosas                                                0xf3b08060 /* isb */,
9275f0984d40SFabiano Rosas                                                0xf3e08000 /* mrs */,
9276f0984d40SFabiano Rosas                                                0xf000d000 /* bl */};
9277f0984d40SFabiano Rosas         static const uint32_t armv6m_mask[] = {0xffe0d000,
9278f0984d40SFabiano Rosas                                                0xfff0d0f0,
9279f0984d40SFabiano Rosas                                                0xfff0d0f0,
9280f0984d40SFabiano Rosas                                                0xfff0d0f0,
9281f0984d40SFabiano Rosas                                                0xffe0d000,
9282f0984d40SFabiano Rosas                                                0xf800d000};
9283f0984d40SFabiano Rosas 
9284f0984d40SFabiano Rosas         for (i = 0; i < ARRAY_SIZE(armv6m_insn); i++) {
9285f0984d40SFabiano Rosas             if ((insn & armv6m_mask[i]) == armv6m_insn[i]) {
9286f0984d40SFabiano Rosas                 found = true;
9287f0984d40SFabiano Rosas                 break;
9288f0984d40SFabiano Rosas             }
9289f0984d40SFabiano Rosas         }
9290f0984d40SFabiano Rosas         if (!found) {
9291f0984d40SFabiano Rosas             goto illegal_op;
9292f0984d40SFabiano Rosas         }
9293f0984d40SFabiano Rosas     } else if ((insn & 0xf800e800) != 0xf000e800)  {
9294f0984d40SFabiano Rosas         if (!arm_dc_feature(s, ARM_FEATURE_THUMB2)) {
9295f0984d40SFabiano Rosas             unallocated_encoding(s);
9296f0984d40SFabiano Rosas             return;
9297f0984d40SFabiano Rosas         }
9298f0984d40SFabiano Rosas     }
9299f0984d40SFabiano Rosas 
9300f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_M)) {
9301f0984d40SFabiano Rosas         /*
9302f0984d40SFabiano Rosas          * NOCP takes precedence over any UNDEF for (almost) the
9303f0984d40SFabiano Rosas          * entire wide range of coprocessor-space encodings, so check
9304f0984d40SFabiano Rosas          * for it first before proceeding to actually decode eg VFP
9305f0984d40SFabiano Rosas          * insns. This decode also handles the few insns which are
9306f0984d40SFabiano Rosas          * in copro space but do not have NOCP checks (eg VLLDM, VLSTM).
9307f0984d40SFabiano Rosas          */
9308f0984d40SFabiano Rosas         if (disas_m_nocp(s, insn)) {
9309f0984d40SFabiano Rosas             return;
9310f0984d40SFabiano Rosas         }
9311f0984d40SFabiano Rosas     }
9312f0984d40SFabiano Rosas 
9313f0984d40SFabiano Rosas     if ((insn & 0xef000000) == 0xef000000) {
9314f0984d40SFabiano Rosas         /*
9315f0984d40SFabiano Rosas          * T32 encodings 0b111p_1111_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq
9316f0984d40SFabiano Rosas          * transform into
9317f0984d40SFabiano Rosas          * A32 encodings 0b1111_001p_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq
9318f0984d40SFabiano Rosas          */
9319f0984d40SFabiano Rosas         uint32_t a32_insn = (insn & 0xe2ffffff) |
9320f0984d40SFabiano Rosas             ((insn & (1 << 28)) >> 4) | (1 << 28);
9321f0984d40SFabiano Rosas 
9322f0984d40SFabiano Rosas         if (disas_neon_dp(s, a32_insn)) {
9323f0984d40SFabiano Rosas             return;
9324f0984d40SFabiano Rosas         }
9325f0984d40SFabiano Rosas     }
9326f0984d40SFabiano Rosas 
9327f0984d40SFabiano Rosas     if ((insn & 0xff100000) == 0xf9000000) {
9328f0984d40SFabiano Rosas         /*
9329f0984d40SFabiano Rosas          * T32 encodings 0b1111_1001_ppp0_qqqq_qqqq_qqqq_qqqq_qqqq
9330f0984d40SFabiano Rosas          * transform into
9331f0984d40SFabiano Rosas          * A32 encodings 0b1111_0100_ppp0_qqqq_qqqq_qqqq_qqqq_qqqq
9332f0984d40SFabiano Rosas          */
9333f0984d40SFabiano Rosas         uint32_t a32_insn = (insn & 0x00ffffff) | 0xf4000000;
9334f0984d40SFabiano Rosas 
9335f0984d40SFabiano Rosas         if (disas_neon_ls(s, a32_insn)) {
9336f0984d40SFabiano Rosas             return;
9337f0984d40SFabiano Rosas         }
9338f0984d40SFabiano Rosas     }
9339f0984d40SFabiano Rosas 
9340f0984d40SFabiano Rosas     /*
9341f0984d40SFabiano Rosas      * TODO: Perhaps merge these into one decodetree output file.
9342f0984d40SFabiano Rosas      * Note disas_vfp is written for a32 with cond field in the
9343f0984d40SFabiano Rosas      * top nibble.  The t32 encoding requires 0xe in the top nibble.
9344f0984d40SFabiano Rosas      */
9345f0984d40SFabiano Rosas     if (disas_t32(s, insn) ||
9346f0984d40SFabiano Rosas         disas_vfp_uncond(s, insn) ||
9347f0984d40SFabiano Rosas         disas_neon_shared(s, insn) ||
9348f0984d40SFabiano Rosas         disas_mve(s, insn) ||
9349f0984d40SFabiano Rosas         ((insn >> 28) == 0xe && disas_vfp(s, insn))) {
9350f0984d40SFabiano Rosas         return;
9351f0984d40SFabiano Rosas     }
9352f0984d40SFabiano Rosas 
9353f0984d40SFabiano Rosas illegal_op:
9354f0984d40SFabiano Rosas     unallocated_encoding(s);
9355f0984d40SFabiano Rosas }
9356f0984d40SFabiano Rosas 
9357f0984d40SFabiano Rosas static void disas_thumb_insn(DisasContext *s, uint32_t insn)
9358f0984d40SFabiano Rosas {
9359f0984d40SFabiano Rosas     if (!disas_t16(s, insn)) {
9360f0984d40SFabiano Rosas         unallocated_encoding(s);
9361f0984d40SFabiano Rosas     }
9362f0984d40SFabiano Rosas }
9363f0984d40SFabiano Rosas 
9364f0984d40SFabiano Rosas static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
9365f0984d40SFabiano Rosas {
9366f0984d40SFabiano Rosas     /* Return true if the insn at dc->base.pc_next might cross a page boundary.
9367f0984d40SFabiano Rosas      * (False positives are OK, false negatives are not.)
9368f0984d40SFabiano Rosas      * We know this is a Thumb insn, and our caller ensures we are
9369f0984d40SFabiano Rosas      * only called if dc->base.pc_next is less than 4 bytes from the page
9370f0984d40SFabiano Rosas      * boundary, so we cross the page if the first 16 bits indicate
9371f0984d40SFabiano Rosas      * that this is a 32 bit insn.
9372f0984d40SFabiano Rosas      */
9373f0984d40SFabiano Rosas     uint16_t insn = arm_lduw_code(env, &s->base, s->base.pc_next, s->sctlr_b);
9374f0984d40SFabiano Rosas 
9375f0984d40SFabiano Rosas     return !thumb_insn_is_16bit(s, s->base.pc_next, insn);
9376f0984d40SFabiano Rosas }
9377f0984d40SFabiano Rosas 
9378f0984d40SFabiano Rosas static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
9379f0984d40SFabiano Rosas {
9380f0984d40SFabiano Rosas     DisasContext *dc = container_of(dcbase, DisasContext, base);
9381f0984d40SFabiano Rosas     CPUARMState *env = cs->env_ptr;
9382f0984d40SFabiano Rosas     ARMCPU *cpu = env_archcpu(env);
9383f0984d40SFabiano Rosas     CPUARMTBFlags tb_flags = arm_tbflags_from_tb(dc->base.tb);
9384f0984d40SFabiano Rosas     uint32_t condexec, core_mmu_idx;
9385f0984d40SFabiano Rosas 
9386f0984d40SFabiano Rosas     dc->isar = &cpu->isar;
9387f0984d40SFabiano Rosas     dc->condjmp = 0;
9388f0984d40SFabiano Rosas     dc->pc_save = dc->base.pc_first;
9389f0984d40SFabiano Rosas     dc->aarch64 = false;
9390f0984d40SFabiano Rosas     dc->thumb = EX_TBFLAG_AM32(tb_flags, THUMB);
9391f0984d40SFabiano Rosas     dc->be_data = EX_TBFLAG_ANY(tb_flags, BE_DATA) ? MO_BE : MO_LE;
9392f0984d40SFabiano Rosas     condexec = EX_TBFLAG_AM32(tb_flags, CONDEXEC);
9393f0984d40SFabiano Rosas     /*
9394f0984d40SFabiano Rosas      * the CONDEXEC TB flags are CPSR bits [15:10][26:25]. On A-profile this
9395f0984d40SFabiano Rosas      * is always the IT bits. On M-profile, some of the reserved encodings
9396f0984d40SFabiano Rosas      * of IT are used instead to indicate either ICI or ECI, which
9397f0984d40SFabiano Rosas      * indicate partial progress of a restartable insn that was interrupted
9398f0984d40SFabiano Rosas      * partway through by an exception:
9399f0984d40SFabiano Rosas      *  * if CONDEXEC[3:0] != 0b0000 : CONDEXEC is IT bits
9400f0984d40SFabiano Rosas      *  * if CONDEXEC[3:0] == 0b0000 : CONDEXEC is ICI or ECI bits
9401f0984d40SFabiano Rosas      * In all cases CONDEXEC == 0 means "not in IT block or restartable
9402f0984d40SFabiano Rosas      * insn, behave normally".
9403f0984d40SFabiano Rosas      */
9404f0984d40SFabiano Rosas     dc->eci = dc->condexec_mask = dc->condexec_cond = 0;
9405f0984d40SFabiano Rosas     dc->eci_handled = false;
9406f0984d40SFabiano Rosas     if (condexec & 0xf) {
9407f0984d40SFabiano Rosas         dc->condexec_mask = (condexec & 0xf) << 1;
9408f0984d40SFabiano Rosas         dc->condexec_cond = condexec >> 4;
9409f0984d40SFabiano Rosas     } else {
9410f0984d40SFabiano Rosas         if (arm_feature(env, ARM_FEATURE_M)) {
9411f0984d40SFabiano Rosas             dc->eci = condexec >> 4;
9412f0984d40SFabiano Rosas         }
9413f0984d40SFabiano Rosas     }
9414f0984d40SFabiano Rosas 
9415f0984d40SFabiano Rosas     core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX);
9416f0984d40SFabiano Rosas     dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
9417f0984d40SFabiano Rosas     dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
9418f0984d40SFabiano Rosas #if !defined(CONFIG_USER_ONLY)
9419f0984d40SFabiano Rosas     dc->user = (dc->current_el == 0);
9420f0984d40SFabiano Rosas #endif
9421f0984d40SFabiano Rosas     dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
9422f0984d40SFabiano Rosas     dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
9423f0984d40SFabiano Rosas     dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
9424f0984d40SFabiano Rosas     dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE);
9425f0984d40SFabiano Rosas     dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC);
9426f0984d40SFabiano Rosas 
9427f0984d40SFabiano Rosas     if (arm_feature(env, ARM_FEATURE_M)) {
9428f0984d40SFabiano Rosas         dc->vfp_enabled = 1;
9429f0984d40SFabiano Rosas         dc->be_data = MO_TE;
9430f0984d40SFabiano Rosas         dc->v7m_handler_mode = EX_TBFLAG_M32(tb_flags, HANDLER);
9431f0984d40SFabiano Rosas         dc->v8m_secure = EX_TBFLAG_M32(tb_flags, SECURE);
9432f0984d40SFabiano Rosas         dc->v8m_stackcheck = EX_TBFLAG_M32(tb_flags, STACKCHECK);
9433f0984d40SFabiano Rosas         dc->v8m_fpccr_s_wrong = EX_TBFLAG_M32(tb_flags, FPCCR_S_WRONG);
9434f0984d40SFabiano Rosas         dc->v7m_new_fp_ctxt_needed =
9435f0984d40SFabiano Rosas             EX_TBFLAG_M32(tb_flags, NEW_FP_CTXT_NEEDED);
9436f0984d40SFabiano Rosas         dc->v7m_lspact = EX_TBFLAG_M32(tb_flags, LSPACT);
9437f0984d40SFabiano Rosas         dc->mve_no_pred = EX_TBFLAG_M32(tb_flags, MVE_NO_PRED);
9438f0984d40SFabiano Rosas     } else {
9439f0984d40SFabiano Rosas         dc->sctlr_b = EX_TBFLAG_A32(tb_flags, SCTLR__B);
9440f0984d40SFabiano Rosas         dc->hstr_active = EX_TBFLAG_A32(tb_flags, HSTR_ACTIVE);
9441f0984d40SFabiano Rosas         dc->ns = EX_TBFLAG_A32(tb_flags, NS);
9442f0984d40SFabiano Rosas         dc->vfp_enabled = EX_TBFLAG_A32(tb_flags, VFPEN);
9443f0984d40SFabiano Rosas         if (arm_feature(env, ARM_FEATURE_XSCALE)) {
9444f0984d40SFabiano Rosas             dc->c15_cpar = EX_TBFLAG_A32(tb_flags, XSCALE_CPAR);
9445f0984d40SFabiano Rosas         } else {
9446f0984d40SFabiano Rosas             dc->vec_len = EX_TBFLAG_A32(tb_flags, VECLEN);
9447f0984d40SFabiano Rosas             dc->vec_stride = EX_TBFLAG_A32(tb_flags, VECSTRIDE);
9448f0984d40SFabiano Rosas         }
9449f0984d40SFabiano Rosas         dc->sme_trap_nonstreaming =
9450f0984d40SFabiano Rosas             EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING);
9451f0984d40SFabiano Rosas     }
9452f0984d40SFabiano Rosas     dc->cp_regs = cpu->cp_regs;
9453f0984d40SFabiano Rosas     dc->features = env->features;
9454f0984d40SFabiano Rosas 
9455f0984d40SFabiano Rosas     /* Single step state. The code-generation logic here is:
9456f0984d40SFabiano Rosas      *  SS_ACTIVE == 0:
9457f0984d40SFabiano Rosas      *   generate code with no special handling for single-stepping (except
9458f0984d40SFabiano Rosas      *   that anything that can make us go to SS_ACTIVE == 1 must end the TB;
9459f0984d40SFabiano Rosas      *   this happens anyway because those changes are all system register or
9460f0984d40SFabiano Rosas      *   PSTATE writes).
9461f0984d40SFabiano Rosas      *  SS_ACTIVE == 1, PSTATE.SS == 1: (active-not-pending)
9462f0984d40SFabiano Rosas      *   emit code for one insn
9463f0984d40SFabiano Rosas      *   emit code to clear PSTATE.SS
9464f0984d40SFabiano Rosas      *   emit code to generate software step exception for completed step
9465f0984d40SFabiano Rosas      *   end TB (as usual for having generated an exception)
9466f0984d40SFabiano Rosas      *  SS_ACTIVE == 1, PSTATE.SS == 0: (active-pending)
9467f0984d40SFabiano Rosas      *   emit code to generate a software step exception
9468f0984d40SFabiano Rosas      *   end the TB
9469f0984d40SFabiano Rosas      */
9470f0984d40SFabiano Rosas     dc->ss_active = EX_TBFLAG_ANY(tb_flags, SS_ACTIVE);
9471f0984d40SFabiano Rosas     dc->pstate_ss = EX_TBFLAG_ANY(tb_flags, PSTATE__SS);
9472f0984d40SFabiano Rosas     dc->is_ldex = false;
9473f0984d40SFabiano Rosas 
9474f0984d40SFabiano Rosas     dc->page_start = dc->base.pc_first & TARGET_PAGE_MASK;
9475f0984d40SFabiano Rosas 
9476f0984d40SFabiano Rosas     /* If architectural single step active, limit to 1.  */
9477f0984d40SFabiano Rosas     if (dc->ss_active) {
9478f0984d40SFabiano Rosas         dc->base.max_insns = 1;
9479f0984d40SFabiano Rosas     }
9480f0984d40SFabiano Rosas 
9481f0984d40SFabiano Rosas     /* ARM is a fixed-length ISA.  Bound the number of insns to execute
9482f0984d40SFabiano Rosas        to those left on the page.  */
9483f0984d40SFabiano Rosas     if (!dc->thumb) {
9484f0984d40SFabiano Rosas         int bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
9485f0984d40SFabiano Rosas         dc->base.max_insns = MIN(dc->base.max_insns, bound);
9486f0984d40SFabiano Rosas     }
9487f0984d40SFabiano Rosas 
9488f0984d40SFabiano Rosas     cpu_V0 = tcg_temp_new_i64();
9489f0984d40SFabiano Rosas     cpu_V1 = tcg_temp_new_i64();
9490f0984d40SFabiano Rosas     cpu_M0 = tcg_temp_new_i64();
9491f0984d40SFabiano Rosas }
9492f0984d40SFabiano Rosas 
9493f0984d40SFabiano Rosas static void arm_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
9494f0984d40SFabiano Rosas {
9495f0984d40SFabiano Rosas     DisasContext *dc = container_of(dcbase, DisasContext, base);
9496f0984d40SFabiano Rosas 
9497f0984d40SFabiano Rosas     /* A note on handling of the condexec (IT) bits:
9498f0984d40SFabiano Rosas      *
9499f0984d40SFabiano Rosas      * We want to avoid the overhead of having to write the updated condexec
9500f0984d40SFabiano Rosas      * bits back to the CPUARMState for every instruction in an IT block. So:
9501f0984d40SFabiano Rosas      * (1) if the condexec bits are not already zero then we write
9502f0984d40SFabiano Rosas      * zero back into the CPUARMState now. This avoids complications trying
9503f0984d40SFabiano Rosas      * to do it at the end of the block. (For example if we don't do this
9504f0984d40SFabiano Rosas      * it's hard to identify whether we can safely skip writing condexec
9505f0984d40SFabiano Rosas      * at the end of the TB, which we definitely want to do for the case
9506f0984d40SFabiano Rosas      * where a TB doesn't do anything with the IT state at all.)
9507f0984d40SFabiano Rosas      * (2) if we are going to leave the TB then we call gen_set_condexec()
9508f0984d40SFabiano Rosas      * which will write the correct value into CPUARMState if zero is wrong.
9509f0984d40SFabiano Rosas      * This is done both for leaving the TB at the end, and for leaving
9510f0984d40SFabiano Rosas      * it because of an exception we know will happen, which is done in
9511f0984d40SFabiano Rosas      * gen_exception_insn(). The latter is necessary because we need to
9512f0984d40SFabiano Rosas      * leave the TB with the PC/IT state just prior to execution of the
9513f0984d40SFabiano Rosas      * instruction which caused the exception.
9514f0984d40SFabiano Rosas      * (3) if we leave the TB unexpectedly (eg a data abort on a load)
9515f0984d40SFabiano Rosas      * then the CPUARMState will be wrong and we need to reset it.
9516f0984d40SFabiano Rosas      * This is handled in the same way as restoration of the
9517f0984d40SFabiano Rosas      * PC in these situations; we save the value of the condexec bits
9518f0984d40SFabiano Rosas      * for each PC via tcg_gen_insn_start(), and restore_state_to_opc()
9519f0984d40SFabiano Rosas      * then uses this to restore them after an exception.
9520f0984d40SFabiano Rosas      *
9521f0984d40SFabiano Rosas      * Note that there are no instructions which can read the condexec
9522f0984d40SFabiano Rosas      * bits, and none which can write non-static values to them, so
9523f0984d40SFabiano Rosas      * we don't need to care about whether CPUARMState is correct in the
9524f0984d40SFabiano Rosas      * middle of a TB.
9525f0984d40SFabiano Rosas      */
9526f0984d40SFabiano Rosas 
9527f0984d40SFabiano Rosas     /* Reset the conditional execution bits immediately. This avoids
9528f0984d40SFabiano Rosas        complications trying to do it at the end of the block.  */
9529f0984d40SFabiano Rosas     if (dc->condexec_mask || dc->condexec_cond) {
9530f0984d40SFabiano Rosas         store_cpu_field_constant(0, condexec_bits);
9531f0984d40SFabiano Rosas     }
9532f0984d40SFabiano Rosas }
9533f0984d40SFabiano Rosas 
9534f0984d40SFabiano Rosas static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
9535f0984d40SFabiano Rosas {
9536f0984d40SFabiano Rosas     DisasContext *dc = container_of(dcbase, DisasContext, base);
9537f0984d40SFabiano Rosas     /*
9538f0984d40SFabiano Rosas      * The ECI/ICI bits share PSR bits with the IT bits, so we
9539f0984d40SFabiano Rosas      * need to reconstitute the bits from the split-out DisasContext
9540f0984d40SFabiano Rosas      * fields here.
9541f0984d40SFabiano Rosas      */
9542f0984d40SFabiano Rosas     uint32_t condexec_bits;
9543f0984d40SFabiano Rosas     target_ulong pc_arg = dc->base.pc_next;
9544f0984d40SFabiano Rosas 
954503a648c4SAnton Johansson     if (tb_cflags(dcbase->tb) & CF_PCREL) {
9546f0984d40SFabiano Rosas         pc_arg &= ~TARGET_PAGE_MASK;
9547f0984d40SFabiano Rosas     }
9548f0984d40SFabiano Rosas     if (dc->eci) {
9549f0984d40SFabiano Rosas         condexec_bits = dc->eci << 4;
9550f0984d40SFabiano Rosas     } else {
9551f0984d40SFabiano Rosas         condexec_bits = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1);
9552f0984d40SFabiano Rosas     }
9553f0984d40SFabiano Rosas     tcg_gen_insn_start(pc_arg, condexec_bits, 0);
9554f0984d40SFabiano Rosas     dc->insn_start = tcg_last_op();
9555f0984d40SFabiano Rosas }
9556f0984d40SFabiano Rosas 
9557f0984d40SFabiano Rosas static bool arm_check_kernelpage(DisasContext *dc)
9558f0984d40SFabiano Rosas {
9559f0984d40SFabiano Rosas #ifdef CONFIG_USER_ONLY
9560f0984d40SFabiano Rosas     /* Intercept jump to the magic kernel page.  */
9561f0984d40SFabiano Rosas     if (dc->base.pc_next >= 0xffff0000) {
9562f0984d40SFabiano Rosas         /* We always get here via a jump, so know we are not in a
9563f0984d40SFabiano Rosas            conditional execution block.  */
9564f0984d40SFabiano Rosas         gen_exception_internal(EXCP_KERNEL_TRAP);
9565f0984d40SFabiano Rosas         dc->base.is_jmp = DISAS_NORETURN;
9566f0984d40SFabiano Rosas         return true;
9567f0984d40SFabiano Rosas     }
9568f0984d40SFabiano Rosas #endif
9569f0984d40SFabiano Rosas     return false;
9570f0984d40SFabiano Rosas }
9571f0984d40SFabiano Rosas 
9572f0984d40SFabiano Rosas static bool arm_check_ss_active(DisasContext *dc)
9573f0984d40SFabiano Rosas {
9574f0984d40SFabiano Rosas     if (dc->ss_active && !dc->pstate_ss) {
9575f0984d40SFabiano Rosas         /* Singlestep state is Active-pending.
9576f0984d40SFabiano Rosas          * If we're in this state at the start of a TB then either
9577f0984d40SFabiano Rosas          *  a) we just took an exception to an EL which is being debugged
9578f0984d40SFabiano Rosas          *     and this is the first insn in the exception handler
9579f0984d40SFabiano Rosas          *  b) debug exceptions were masked and we just unmasked them
9580f0984d40SFabiano Rosas          *     without changing EL (eg by clearing PSTATE.D)
9581f0984d40SFabiano Rosas          * In either case we're going to take a swstep exception in the
9582f0984d40SFabiano Rosas          * "did not step an insn" case, and so the syndrome ISV and EX
9583f0984d40SFabiano Rosas          * bits should be zero.
9584f0984d40SFabiano Rosas          */
9585f0984d40SFabiano Rosas         assert(dc->base.num_insns == 1);
9586f0984d40SFabiano Rosas         gen_swstep_exception(dc, 0, 0);
9587f0984d40SFabiano Rosas         dc->base.is_jmp = DISAS_NORETURN;
9588f0984d40SFabiano Rosas         return true;
9589f0984d40SFabiano Rosas     }
9590f0984d40SFabiano Rosas 
9591f0984d40SFabiano Rosas     return false;
9592f0984d40SFabiano Rosas }
9593f0984d40SFabiano Rosas 
9594f0984d40SFabiano Rosas static void arm_post_translate_insn(DisasContext *dc)
9595f0984d40SFabiano Rosas {
9596f0984d40SFabiano Rosas     if (dc->condjmp && dc->base.is_jmp == DISAS_NEXT) {
9597f0984d40SFabiano Rosas         if (dc->pc_save != dc->condlabel.pc_save) {
9598f0984d40SFabiano Rosas             gen_update_pc(dc, dc->condlabel.pc_save - dc->pc_save);
9599f0984d40SFabiano Rosas         }
9600f0984d40SFabiano Rosas         gen_set_label(dc->condlabel.label);
9601f0984d40SFabiano Rosas         dc->condjmp = 0;
9602f0984d40SFabiano Rosas     }
9603f0984d40SFabiano Rosas     translator_loop_temp_check(&dc->base);
9604f0984d40SFabiano Rosas }
9605f0984d40SFabiano Rosas 
9606f0984d40SFabiano Rosas static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
9607f0984d40SFabiano Rosas {
9608f0984d40SFabiano Rosas     DisasContext *dc = container_of(dcbase, DisasContext, base);
9609f0984d40SFabiano Rosas     CPUARMState *env = cpu->env_ptr;
9610f0984d40SFabiano Rosas     uint32_t pc = dc->base.pc_next;
9611f0984d40SFabiano Rosas     unsigned int insn;
9612f0984d40SFabiano Rosas 
9613f0984d40SFabiano Rosas     /* Singlestep exceptions have the highest priority. */
9614f0984d40SFabiano Rosas     if (arm_check_ss_active(dc)) {
9615f0984d40SFabiano Rosas         dc->base.pc_next = pc + 4;
9616f0984d40SFabiano Rosas         return;
9617f0984d40SFabiano Rosas     }
9618f0984d40SFabiano Rosas 
9619f0984d40SFabiano Rosas     if (pc & 3) {
9620f0984d40SFabiano Rosas         /*
9621f0984d40SFabiano Rosas          * PC alignment fault.  This has priority over the instruction abort
9622f0984d40SFabiano Rosas          * that we would receive from a translation fault via arm_ldl_code
9623f0984d40SFabiano Rosas          * (or the execution of the kernelpage entrypoint). This should only
9624f0984d40SFabiano Rosas          * be possible after an indirect branch, at the start of the TB.
9625f0984d40SFabiano Rosas          */
9626f0984d40SFabiano Rosas         assert(dc->base.num_insns == 1);
9627f0984d40SFabiano Rosas         gen_helper_exception_pc_alignment(cpu_env, tcg_constant_tl(pc));
9628f0984d40SFabiano Rosas         dc->base.is_jmp = DISAS_NORETURN;
9629f0984d40SFabiano Rosas         dc->base.pc_next = QEMU_ALIGN_UP(pc, 4);
9630f0984d40SFabiano Rosas         return;
9631f0984d40SFabiano Rosas     }
9632f0984d40SFabiano Rosas 
9633f0984d40SFabiano Rosas     if (arm_check_kernelpage(dc)) {
9634f0984d40SFabiano Rosas         dc->base.pc_next = pc + 4;
9635f0984d40SFabiano Rosas         return;
9636f0984d40SFabiano Rosas     }
9637f0984d40SFabiano Rosas 
9638f0984d40SFabiano Rosas     dc->pc_curr = pc;
9639f0984d40SFabiano Rosas     insn = arm_ldl_code(env, &dc->base, pc, dc->sctlr_b);
9640f0984d40SFabiano Rosas     dc->insn = insn;
9641f0984d40SFabiano Rosas     dc->base.pc_next = pc + 4;
9642f0984d40SFabiano Rosas     disas_arm_insn(dc, insn);
9643f0984d40SFabiano Rosas 
9644f0984d40SFabiano Rosas     arm_post_translate_insn(dc);
9645f0984d40SFabiano Rosas 
9646f0984d40SFabiano Rosas     /* ARM is a fixed-length ISA.  We performed the cross-page check
9647f0984d40SFabiano Rosas        in init_disas_context by adjusting max_insns.  */
9648f0984d40SFabiano Rosas }
9649f0984d40SFabiano Rosas 
9650f0984d40SFabiano Rosas static bool thumb_insn_is_unconditional(DisasContext *s, uint32_t insn)
9651f0984d40SFabiano Rosas {
9652f0984d40SFabiano Rosas     /* Return true if this Thumb insn is always unconditional,
9653f0984d40SFabiano Rosas      * even inside an IT block. This is true of only a very few
9654f0984d40SFabiano Rosas      * instructions: BKPT, HLT, and SG.
9655f0984d40SFabiano Rosas      *
9656f0984d40SFabiano Rosas      * A larger class of instructions are UNPREDICTABLE if used
9657f0984d40SFabiano Rosas      * inside an IT block; we do not need to detect those here, because
9658f0984d40SFabiano Rosas      * what we do by default (perform the cc check and update the IT
9659f0984d40SFabiano Rosas      * bits state machine) is a permitted CONSTRAINED UNPREDICTABLE
9660f0984d40SFabiano Rosas      * choice for those situations.
9661f0984d40SFabiano Rosas      *
9662f0984d40SFabiano Rosas      * insn is either a 16-bit or a 32-bit instruction; the two are
9663f0984d40SFabiano Rosas      * distinguishable because for the 16-bit case the top 16 bits
9664f0984d40SFabiano Rosas      * are zeroes, and that isn't a valid 32-bit encoding.
9665f0984d40SFabiano Rosas      */
9666f0984d40SFabiano Rosas     if ((insn & 0xffffff00) == 0xbe00) {
9667f0984d40SFabiano Rosas         /* BKPT */
9668f0984d40SFabiano Rosas         return true;
9669f0984d40SFabiano Rosas     }
9670f0984d40SFabiano Rosas 
9671f0984d40SFabiano Rosas     if ((insn & 0xffffffc0) == 0xba80 && arm_dc_feature(s, ARM_FEATURE_V8) &&
9672f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_M)) {
9673f0984d40SFabiano Rosas         /* HLT: v8A only. This is unconditional even when it is going to
9674f0984d40SFabiano Rosas          * UNDEF; see the v8A ARM ARM DDI0487B.a H3.3.
9675f0984d40SFabiano Rosas          * For v7 cores this was a plain old undefined encoding and so
9676f0984d40SFabiano Rosas          * honours its cc check. (We might be using the encoding as
9677f0984d40SFabiano Rosas          * a semihosting trap, but we don't change the cc check behaviour
9678f0984d40SFabiano Rosas          * on that account, because a debugger connected to a real v7A
9679f0984d40SFabiano Rosas          * core and emulating semihosting traps by catching the UNDEF
9680f0984d40SFabiano Rosas          * exception would also only see cases where the cc check passed.
9681f0984d40SFabiano Rosas          * No guest code should be trying to do a HLT semihosting trap
9682f0984d40SFabiano Rosas          * in an IT block anyway.
9683f0984d40SFabiano Rosas          */
9684f0984d40SFabiano Rosas         return true;
9685f0984d40SFabiano Rosas     }
9686f0984d40SFabiano Rosas 
9687f0984d40SFabiano Rosas     if (insn == 0xe97fe97f && arm_dc_feature(s, ARM_FEATURE_V8) &&
9688f0984d40SFabiano Rosas         arm_dc_feature(s, ARM_FEATURE_M)) {
9689f0984d40SFabiano Rosas         /* SG: v8M only */
9690f0984d40SFabiano Rosas         return true;
9691f0984d40SFabiano Rosas     }
9692f0984d40SFabiano Rosas 
9693f0984d40SFabiano Rosas     return false;
9694f0984d40SFabiano Rosas }
9695f0984d40SFabiano Rosas 
9696f0984d40SFabiano Rosas static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
9697f0984d40SFabiano Rosas {
9698f0984d40SFabiano Rosas     DisasContext *dc = container_of(dcbase, DisasContext, base);
9699f0984d40SFabiano Rosas     CPUARMState *env = cpu->env_ptr;
9700f0984d40SFabiano Rosas     uint32_t pc = dc->base.pc_next;
9701f0984d40SFabiano Rosas     uint32_t insn;
9702f0984d40SFabiano Rosas     bool is_16bit;
9703f0984d40SFabiano Rosas     /* TCG op to rewind to if this turns out to be an invalid ECI state */
9704f0984d40SFabiano Rosas     TCGOp *insn_eci_rewind = NULL;
9705f0984d40SFabiano Rosas     target_ulong insn_eci_pc_save = -1;
9706f0984d40SFabiano Rosas 
9707f0984d40SFabiano Rosas     /* Misaligned thumb PC is architecturally impossible. */
9708f0984d40SFabiano Rosas     assert((dc->base.pc_next & 1) == 0);
9709f0984d40SFabiano Rosas 
9710f0984d40SFabiano Rosas     if (arm_check_ss_active(dc) || arm_check_kernelpage(dc)) {
9711f0984d40SFabiano Rosas         dc->base.pc_next = pc + 2;
9712f0984d40SFabiano Rosas         return;
9713f0984d40SFabiano Rosas     }
9714f0984d40SFabiano Rosas 
9715f0984d40SFabiano Rosas     dc->pc_curr = pc;
9716f0984d40SFabiano Rosas     insn = arm_lduw_code(env, &dc->base, pc, dc->sctlr_b);
9717f0984d40SFabiano Rosas     is_16bit = thumb_insn_is_16bit(dc, dc->base.pc_next, insn);
9718f0984d40SFabiano Rosas     pc += 2;
9719f0984d40SFabiano Rosas     if (!is_16bit) {
9720f0984d40SFabiano Rosas         uint32_t insn2 = arm_lduw_code(env, &dc->base, pc, dc->sctlr_b);
9721f0984d40SFabiano Rosas         insn = insn << 16 | insn2;
9722f0984d40SFabiano Rosas         pc += 2;
9723f0984d40SFabiano Rosas     }
9724f0984d40SFabiano Rosas     dc->base.pc_next = pc;
9725f0984d40SFabiano Rosas     dc->insn = insn;
9726f0984d40SFabiano Rosas 
9727f0984d40SFabiano Rosas     if (dc->pstate_il) {
9728f0984d40SFabiano Rosas         /*
9729f0984d40SFabiano Rosas          * Illegal execution state. This has priority over BTI
9730f0984d40SFabiano Rosas          * exceptions, but comes after instruction abort exceptions.
9731f0984d40SFabiano Rosas          */
9732f0984d40SFabiano Rosas         gen_exception_insn(dc, 0, EXCP_UDEF, syn_illegalstate());
9733f0984d40SFabiano Rosas         return;
9734f0984d40SFabiano Rosas     }
9735f0984d40SFabiano Rosas 
9736f0984d40SFabiano Rosas     if (dc->eci) {
9737f0984d40SFabiano Rosas         /*
9738f0984d40SFabiano Rosas          * For M-profile continuable instructions, ECI/ICI handling
9739f0984d40SFabiano Rosas          * falls into these cases:
9740f0984d40SFabiano Rosas          *  - interrupt-continuable instructions
9741f0984d40SFabiano Rosas          *     These are the various load/store multiple insns (both
9742f0984d40SFabiano Rosas          *     integer and fp). The ICI bits indicate the register
9743f0984d40SFabiano Rosas          *     where the load/store can resume. We make the IMPDEF
9744f0984d40SFabiano Rosas          *     choice to always do "instruction restart", ie ignore
9745f0984d40SFabiano Rosas          *     the ICI value and always execute the ldm/stm from the
9746f0984d40SFabiano Rosas          *     start. So all we need to do is zero PSR.ICI if the
9747f0984d40SFabiano Rosas          *     insn executes.
9748f0984d40SFabiano Rosas          *  - MVE instructions subject to beat-wise execution
9749f0984d40SFabiano Rosas          *     Here the ECI bits indicate which beats have already been
9750f0984d40SFabiano Rosas          *     executed, and we must honour this. Each insn of this
9751f0984d40SFabiano Rosas          *     type will handle it correctly. We will update PSR.ECI
9752f0984d40SFabiano Rosas          *     in the helper function for the insn (some ECI values
9753f0984d40SFabiano Rosas          *     mean that the following insn also has been partially
9754f0984d40SFabiano Rosas          *     executed).
9755f0984d40SFabiano Rosas          *  - Special cases which don't advance ECI
9756f0984d40SFabiano Rosas          *     The insns LE, LETP and BKPT leave the ECI/ICI state
9757f0984d40SFabiano Rosas          *     bits untouched.
9758f0984d40SFabiano Rosas          *  - all other insns (the common case)
9759f0984d40SFabiano Rosas          *     Non-zero ECI/ICI means an INVSTATE UsageFault.
9760f0984d40SFabiano Rosas          *     We place a rewind-marker here. Insns in the previous
9761f0984d40SFabiano Rosas          *     three categories will set a flag in the DisasContext.
9762f0984d40SFabiano Rosas          *     If the flag isn't set after we call disas_thumb_insn()
9763f0984d40SFabiano Rosas          *     or disas_thumb2_insn() then we know we have a "some other
9764f0984d40SFabiano Rosas          *     insn" case. We will rewind to the marker (ie throwing away
9765f0984d40SFabiano Rosas          *     all the generated code) and instead emit "take exception".
9766f0984d40SFabiano Rosas          */
9767f0984d40SFabiano Rosas         insn_eci_rewind = tcg_last_op();
9768f0984d40SFabiano Rosas         insn_eci_pc_save = dc->pc_save;
9769f0984d40SFabiano Rosas     }
9770f0984d40SFabiano Rosas 
9771f0984d40SFabiano Rosas     if (dc->condexec_mask && !thumb_insn_is_unconditional(dc, insn)) {
9772f0984d40SFabiano Rosas         uint32_t cond = dc->condexec_cond;
9773f0984d40SFabiano Rosas 
9774f0984d40SFabiano Rosas         /*
9775f0984d40SFabiano Rosas          * Conditionally skip the insn. Note that both 0xe and 0xf mean
9776f0984d40SFabiano Rosas          * "always"; 0xf is not "never".
9777f0984d40SFabiano Rosas          */
9778f0984d40SFabiano Rosas         if (cond < 0x0e) {
9779f0984d40SFabiano Rosas             arm_skip_unless(dc, cond);
9780f0984d40SFabiano Rosas         }
9781f0984d40SFabiano Rosas     }
9782f0984d40SFabiano Rosas 
9783f0984d40SFabiano Rosas     if (is_16bit) {
9784f0984d40SFabiano Rosas         disas_thumb_insn(dc, insn);
9785f0984d40SFabiano Rosas     } else {
9786f0984d40SFabiano Rosas         disas_thumb2_insn(dc, insn);
9787f0984d40SFabiano Rosas     }
9788f0984d40SFabiano Rosas 
9789f0984d40SFabiano Rosas     /* Advance the Thumb condexec condition.  */
9790f0984d40SFabiano Rosas     if (dc->condexec_mask) {
9791f0984d40SFabiano Rosas         dc->condexec_cond = ((dc->condexec_cond & 0xe) |
9792f0984d40SFabiano Rosas                              ((dc->condexec_mask >> 4) & 1));
9793f0984d40SFabiano Rosas         dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
9794f0984d40SFabiano Rosas         if (dc->condexec_mask == 0) {
9795f0984d40SFabiano Rosas             dc->condexec_cond = 0;
9796f0984d40SFabiano Rosas         }
9797f0984d40SFabiano Rosas     }
9798f0984d40SFabiano Rosas 
9799f0984d40SFabiano Rosas     if (dc->eci && !dc->eci_handled) {
9800f0984d40SFabiano Rosas         /*
9801f0984d40SFabiano Rosas          * Insn wasn't valid for ECI/ICI at all: undo what we
9802f0984d40SFabiano Rosas          * just generated and instead emit an exception
9803f0984d40SFabiano Rosas          */
9804f0984d40SFabiano Rosas         tcg_remove_ops_after(insn_eci_rewind);
9805f0984d40SFabiano Rosas         dc->pc_save = insn_eci_pc_save;
9806f0984d40SFabiano Rosas         dc->condjmp = 0;
9807f0984d40SFabiano Rosas         gen_exception_insn(dc, 0, EXCP_INVSTATE, syn_uncategorized());
9808f0984d40SFabiano Rosas     }
9809f0984d40SFabiano Rosas 
9810f0984d40SFabiano Rosas     arm_post_translate_insn(dc);
9811f0984d40SFabiano Rosas 
9812f0984d40SFabiano Rosas     /* Thumb is a variable-length ISA.  Stop translation when the next insn
9813f0984d40SFabiano Rosas      * will touch a new page.  This ensures that prefetch aborts occur at
9814f0984d40SFabiano Rosas      * the right place.
9815f0984d40SFabiano Rosas      *
9816f0984d40SFabiano Rosas      * We want to stop the TB if the next insn starts in a new page,
9817f0984d40SFabiano Rosas      * or if it spans between this page and the next. This means that
9818f0984d40SFabiano Rosas      * if we're looking at the last halfword in the page we need to
9819f0984d40SFabiano Rosas      * see if it's a 16-bit Thumb insn (which will fit in this TB)
9820f0984d40SFabiano Rosas      * or a 32-bit Thumb insn (which won't).
9821f0984d40SFabiano Rosas      * This is to avoid generating a silly TB with a single 16-bit insn
9822f0984d40SFabiano Rosas      * in it at the end of this page (which would execute correctly
9823f0984d40SFabiano Rosas      * but isn't very efficient).
9824f0984d40SFabiano Rosas      */
9825f0984d40SFabiano Rosas     if (dc->base.is_jmp == DISAS_NEXT
9826f0984d40SFabiano Rosas         && (dc->base.pc_next - dc->page_start >= TARGET_PAGE_SIZE
9827f0984d40SFabiano Rosas             || (dc->base.pc_next - dc->page_start >= TARGET_PAGE_SIZE - 3
9828f0984d40SFabiano Rosas                 && insn_crosses_page(env, dc)))) {
9829f0984d40SFabiano Rosas         dc->base.is_jmp = DISAS_TOO_MANY;
9830f0984d40SFabiano Rosas     }
9831f0984d40SFabiano Rosas }
9832f0984d40SFabiano Rosas 
9833f0984d40SFabiano Rosas static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
9834f0984d40SFabiano Rosas {
9835f0984d40SFabiano Rosas     DisasContext *dc = container_of(dcbase, DisasContext, base);
9836f0984d40SFabiano Rosas 
9837f0984d40SFabiano Rosas     /* At this stage dc->condjmp will only be set when the skipped
9838f0984d40SFabiano Rosas        instruction was a conditional branch or trap, and the PC has
9839f0984d40SFabiano Rosas        already been written.  */
9840f0984d40SFabiano Rosas     gen_set_condexec(dc);
9841f0984d40SFabiano Rosas     if (dc->base.is_jmp == DISAS_BX_EXCRET) {
9842f0984d40SFabiano Rosas         /* Exception return branches need some special case code at the
9843f0984d40SFabiano Rosas          * end of the TB, which is complex enough that it has to
9844f0984d40SFabiano Rosas          * handle the single-step vs not and the condition-failed
9845f0984d40SFabiano Rosas          * insn codepath itself.
9846f0984d40SFabiano Rosas          */
9847f0984d40SFabiano Rosas         gen_bx_excret_final_code(dc);
9848f0984d40SFabiano Rosas     } else if (unlikely(dc->ss_active)) {
9849f0984d40SFabiano Rosas         /* Unconditional and "condition passed" instruction codepath. */
9850f0984d40SFabiano Rosas         switch (dc->base.is_jmp) {
9851f0984d40SFabiano Rosas         case DISAS_SWI:
9852f0984d40SFabiano Rosas             gen_ss_advance(dc);
9853f0984d40SFabiano Rosas             gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
9854f0984d40SFabiano Rosas             break;
9855f0984d40SFabiano Rosas         case DISAS_HVC:
9856f0984d40SFabiano Rosas             gen_ss_advance(dc);
9857f0984d40SFabiano Rosas             gen_exception_el(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
9858f0984d40SFabiano Rosas             break;
9859f0984d40SFabiano Rosas         case DISAS_SMC:
9860f0984d40SFabiano Rosas             gen_ss_advance(dc);
9861f0984d40SFabiano Rosas             gen_exception_el(EXCP_SMC, syn_aa32_smc(), 3);
9862f0984d40SFabiano Rosas             break;
9863f0984d40SFabiano Rosas         case DISAS_NEXT:
9864f0984d40SFabiano Rosas         case DISAS_TOO_MANY:
9865f0984d40SFabiano Rosas         case DISAS_UPDATE_EXIT:
9866f0984d40SFabiano Rosas         case DISAS_UPDATE_NOCHAIN:
9867f0984d40SFabiano Rosas             gen_update_pc(dc, curr_insn_len(dc));
9868f0984d40SFabiano Rosas             /* fall through */
9869f0984d40SFabiano Rosas         default:
9870f0984d40SFabiano Rosas             /* FIXME: Single stepping a WFI insn will not halt the CPU. */
9871f0984d40SFabiano Rosas             gen_singlestep_exception(dc);
9872f0984d40SFabiano Rosas             break;
9873f0984d40SFabiano Rosas         case DISAS_NORETURN:
9874f0984d40SFabiano Rosas             break;
9875f0984d40SFabiano Rosas         }
9876f0984d40SFabiano Rosas     } else {
9877f0984d40SFabiano Rosas         /* While branches must always occur at the end of an IT block,
9878f0984d40SFabiano Rosas            there are a few other things that can cause us to terminate
9879f0984d40SFabiano Rosas            the TB in the middle of an IT block:
9880f0984d40SFabiano Rosas             - Exception generating instructions (bkpt, swi, undefined).
9881f0984d40SFabiano Rosas             - Page boundaries.
9882f0984d40SFabiano Rosas             - Hardware watchpoints.
9883f0984d40SFabiano Rosas            Hardware breakpoints have already been handled and skip this code.
9884f0984d40SFabiano Rosas          */
9885f0984d40SFabiano Rosas         switch (dc->base.is_jmp) {
9886f0984d40SFabiano Rosas         case DISAS_NEXT:
9887f0984d40SFabiano Rosas         case DISAS_TOO_MANY:
9888f0984d40SFabiano Rosas             gen_goto_tb(dc, 1, curr_insn_len(dc));
9889f0984d40SFabiano Rosas             break;
9890f0984d40SFabiano Rosas         case DISAS_UPDATE_NOCHAIN:
9891f0984d40SFabiano Rosas             gen_update_pc(dc, curr_insn_len(dc));
9892f0984d40SFabiano Rosas             /* fall through */
9893f0984d40SFabiano Rosas         case DISAS_JUMP:
9894f0984d40SFabiano Rosas             gen_goto_ptr();
9895f0984d40SFabiano Rosas             break;
9896f0984d40SFabiano Rosas         case DISAS_UPDATE_EXIT:
9897f0984d40SFabiano Rosas             gen_update_pc(dc, curr_insn_len(dc));
9898f0984d40SFabiano Rosas             /* fall through */
9899f0984d40SFabiano Rosas         default:
9900f0984d40SFabiano Rosas             /* indicate that the hash table must be used to find the next TB */
9901f0984d40SFabiano Rosas             tcg_gen_exit_tb(NULL, 0);
9902f0984d40SFabiano Rosas             break;
9903f0984d40SFabiano Rosas         case DISAS_NORETURN:
9904f0984d40SFabiano Rosas             /* nothing more to generate */
9905f0984d40SFabiano Rosas             break;
9906f0984d40SFabiano Rosas         case DISAS_WFI:
9907f0984d40SFabiano Rosas             gen_helper_wfi(cpu_env, tcg_constant_i32(curr_insn_len(dc)));
9908f0984d40SFabiano Rosas             /*
9909f0984d40SFabiano Rosas              * The helper doesn't necessarily throw an exception, but we
9910f0984d40SFabiano Rosas              * must go back to the main loop to check for interrupts anyway.
9911f0984d40SFabiano Rosas              */
9912f0984d40SFabiano Rosas             tcg_gen_exit_tb(NULL, 0);
9913f0984d40SFabiano Rosas             break;
9914f0984d40SFabiano Rosas         case DISAS_WFE:
9915f0984d40SFabiano Rosas             gen_helper_wfe(cpu_env);
9916f0984d40SFabiano Rosas             break;
9917f0984d40SFabiano Rosas         case DISAS_YIELD:
9918f0984d40SFabiano Rosas             gen_helper_yield(cpu_env);
9919f0984d40SFabiano Rosas             break;
9920f0984d40SFabiano Rosas         case DISAS_SWI:
9921f0984d40SFabiano Rosas             gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
9922f0984d40SFabiano Rosas             break;
9923f0984d40SFabiano Rosas         case DISAS_HVC:
9924f0984d40SFabiano Rosas             gen_exception_el(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
9925f0984d40SFabiano Rosas             break;
9926f0984d40SFabiano Rosas         case DISAS_SMC:
9927f0984d40SFabiano Rosas             gen_exception_el(EXCP_SMC, syn_aa32_smc(), 3);
9928f0984d40SFabiano Rosas             break;
9929f0984d40SFabiano Rosas         }
9930f0984d40SFabiano Rosas     }
9931f0984d40SFabiano Rosas 
9932f0984d40SFabiano Rosas     if (dc->condjmp) {
9933f0984d40SFabiano Rosas         /* "Condition failed" instruction codepath for the branch/trap insn */
9934f0984d40SFabiano Rosas         set_disas_label(dc, dc->condlabel);
9935f0984d40SFabiano Rosas         gen_set_condexec(dc);
9936f0984d40SFabiano Rosas         if (unlikely(dc->ss_active)) {
9937f0984d40SFabiano Rosas             gen_update_pc(dc, curr_insn_len(dc));
9938f0984d40SFabiano Rosas             gen_singlestep_exception(dc);
9939f0984d40SFabiano Rosas         } else {
9940f0984d40SFabiano Rosas             gen_goto_tb(dc, 1, curr_insn_len(dc));
9941f0984d40SFabiano Rosas         }
9942f0984d40SFabiano Rosas     }
9943f0984d40SFabiano Rosas }
9944f0984d40SFabiano Rosas 
9945f0984d40SFabiano Rosas static void arm_tr_disas_log(const DisasContextBase *dcbase,
9946f0984d40SFabiano Rosas                              CPUState *cpu, FILE *logfile)
9947f0984d40SFabiano Rosas {
9948f0984d40SFabiano Rosas     DisasContext *dc = container_of(dcbase, DisasContext, base);
9949f0984d40SFabiano Rosas 
9950f0984d40SFabiano Rosas     fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
9951f0984d40SFabiano Rosas     target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size);
9952f0984d40SFabiano Rosas }
9953f0984d40SFabiano Rosas 
9954f0984d40SFabiano Rosas static const TranslatorOps arm_translator_ops = {
9955f0984d40SFabiano Rosas     .init_disas_context = arm_tr_init_disas_context,
9956f0984d40SFabiano Rosas     .tb_start           = arm_tr_tb_start,
9957f0984d40SFabiano Rosas     .insn_start         = arm_tr_insn_start,
9958f0984d40SFabiano Rosas     .translate_insn     = arm_tr_translate_insn,
9959f0984d40SFabiano Rosas     .tb_stop            = arm_tr_tb_stop,
9960f0984d40SFabiano Rosas     .disas_log          = arm_tr_disas_log,
9961f0984d40SFabiano Rosas };
9962f0984d40SFabiano Rosas 
9963f0984d40SFabiano Rosas static const TranslatorOps thumb_translator_ops = {
9964f0984d40SFabiano Rosas     .init_disas_context = arm_tr_init_disas_context,
9965f0984d40SFabiano Rosas     .tb_start           = arm_tr_tb_start,
9966f0984d40SFabiano Rosas     .insn_start         = arm_tr_insn_start,
9967f0984d40SFabiano Rosas     .translate_insn     = thumb_tr_translate_insn,
9968f0984d40SFabiano Rosas     .tb_stop            = arm_tr_tb_stop,
9969f0984d40SFabiano Rosas     .disas_log          = arm_tr_disas_log,
9970f0984d40SFabiano Rosas };
9971f0984d40SFabiano Rosas 
9972f0984d40SFabiano Rosas /* generate intermediate code for basic block 'tb'.  */
9973f0984d40SFabiano Rosas void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns,
9974f0984d40SFabiano Rosas                            target_ulong pc, void *host_pc)
9975f0984d40SFabiano Rosas {
9976f0984d40SFabiano Rosas     DisasContext dc = { };
9977f0984d40SFabiano Rosas     const TranslatorOps *ops = &arm_translator_ops;
9978f0984d40SFabiano Rosas     CPUARMTBFlags tb_flags = arm_tbflags_from_tb(tb);
9979f0984d40SFabiano Rosas 
9980f0984d40SFabiano Rosas     if (EX_TBFLAG_AM32(tb_flags, THUMB)) {
9981f0984d40SFabiano Rosas         ops = &thumb_translator_ops;
9982f0984d40SFabiano Rosas     }
9983f0984d40SFabiano Rosas #ifdef TARGET_AARCH64
9984f0984d40SFabiano Rosas     if (EX_TBFLAG_ANY(tb_flags, AARCH64_STATE)) {
9985f0984d40SFabiano Rosas         ops = &aarch64_translator_ops;
9986f0984d40SFabiano Rosas     }
9987f0984d40SFabiano Rosas #endif
9988f0984d40SFabiano Rosas 
9989f0984d40SFabiano Rosas     translator_loop(cpu, tb, max_insns, pc, host_pc, ops, &dc.base);
9990f0984d40SFabiano Rosas }
9991