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