]>
Commit | Line | Data |
---|---|---|
f570c61e AG |
1 | #ifndef TARGET_ARM_TRANSLATE_H |
2 | #define TARGET_ARM_TRANSLATE_H | |
3 | ||
5d05e5a1 RH |
4 | #include "cpu.h" |
5 | #include "tcg/tcg-op.h" | |
6 | #include "tcg/tcg-op-gvec.h" | |
1f17f91d | 7 | #include "exec/exec-all.h" |
77fc6f5e | 8 | #include "exec/translator.h" |
a46f42d9 | 9 | #include "exec/helper-gen.h" |
c1d5f50f | 10 | #include "internals.h" |
77fc6f5e LV |
11 | |
12 | ||
f570c61e | 13 | /* internal defines */ |
abb80995 RH |
14 | |
15 | /* | |
16 | * Save pc_save across a branch, so that we may restore the value from | |
17 | * before the branch at the point the label is emitted. | |
18 | */ | |
19 | typedef struct DisasLabel { | |
20 | TCGLabel *label; | |
21 | target_ulong pc_save; | |
22 | } DisasLabel; | |
23 | ||
f570c61e | 24 | typedef struct DisasContext { |
dcba3a8d | 25 | DisasContextBase base; |
962fcbf2 | 26 | const ARMISARegisters *isar; |
dcba3a8d | 27 | |
43722a6d RH |
28 | /* The address of the current instruction being translated. */ |
29 | target_ulong pc_curr; | |
abb80995 | 30 | /* |
03a648c4 | 31 | * For CF_PCREL, the full value of cpu_pc is not known |
abb80995 RH |
32 | * (although the page offset is known). For convenience, the |
33 | * translation loop uses the full virtual address that triggered | |
34 | * the translation, from base.pc_start through pc_curr. | |
35 | * For efficiency, we do not update cpu_pc for every instruction. | |
36 | * Instead, pc_save has the value of pc_curr at the time of the | |
37 | * last update to cpu_pc, which allows us to compute the addend | |
38 | * needed to bring cpu_pc current: pc_curr - pc_save. | |
39 | * If cpu_pc now contains the destination of an indirect branch, | |
40 | * pc_save contains -1 to indicate that relative updates are no | |
41 | * longer possible. | |
42 | */ | |
43 | target_ulong pc_save; | |
bfe7ad5b | 44 | target_ulong page_start; |
14ade10f | 45 | uint32_t insn; |
f570c61e AG |
46 | /* Nonzero if this instruction has been conditionally skipped. */ |
47 | int condjmp; | |
48 | /* The label that will be jumped to when the instruction is skipped. */ | |
abb80995 | 49 | DisasLabel condlabel; |
f570c61e AG |
50 | /* Thumb-2 conditional execution bits. */ |
51 | int condexec_mask; | |
52 | int condexec_cond; | |
5138bd01 PM |
53 | /* M-profile ECI/ICI exception-continuable instruction state */ |
54 | int eci; | |
55 | /* | |
56 | * trans_ functions for insns which are continuable should set this true | |
57 | * after decode (ie after any UNDEF checks) | |
58 | */ | |
59 | bool eci_handled; | |
f9fd40eb | 60 | int sctlr_b; |
14776ab5 | 61 | MemOp be_data; |
f570c61e AG |
62 | #if !defined(CONFIG_USER_ONLY) |
63 | int user; | |
64 | #endif | |
c1e37810 | 65 | ARMMMUIdx mmu_idx; /* MMU index to use for normal loads/stores */ |
4a9ee99d RH |
66 | uint8_t tbii; /* TBI1|TBI0 for insns */ |
67 | uint8_t tbid; /* TBI1|TBI0 for data */ | |
81ae05fa | 68 | uint8_t tcma; /* TCMA1|TCMA0 for MTE */ |
3f342b9e | 69 | bool ns; /* Use non-secure CPREG bank on access */ |
9dbbc748 | 70 | int fp_excp_el; /* FP exception EL or 0 if enabled */ |
1db5e96c | 71 | int sve_excp_el; /* SVE exception EL or 0 if enabled */ |
6b2ca83e | 72 | int sme_excp_el; /* SME exception EL or 0 if enabled */ |
f45ce4c3 | 73 | int vl; /* current vector length in bytes */ |
5d7953ad | 74 | int svl; /* current streaming vector length in bytes */ |
8c6afa6a | 75 | bool vfp_enabled; /* FP enabled via FPSCR.EN */ |
f570c61e AG |
76 | int vec_len; |
77 | int vec_stride; | |
064c379c | 78 | bool v7m_handler_mode; |
fb602cb7 | 79 | bool v8m_secure; /* true if v8M and we're in Secure mode */ |
4730fb85 | 80 | bool v8m_stackcheck; /* true if we need to perform v8M stack limit checks */ |
6d60c67a | 81 | bool v8m_fpccr_s_wrong; /* true if v8M FPCCR.S != v8m_secure */ |
6000531e | 82 | bool v7m_new_fp_ctxt_needed; /* ASPEN set but no active FP context */ |
e33cf0f8 | 83 | bool v7m_lspact; /* FPCCR.LSPACT set */ |
d4a2dc67 PM |
84 | /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI |
85 | * so that top level loop can generate correct syndrome information. | |
86 | */ | |
87 | uint32_t svc_imm; | |
dcbff19b | 88 | int current_el; |
60322b39 | 89 | GHashTable *cp_regs; |
a984e42c | 90 | uint64_t features; /* CPU features bits */ |
a3bc906f | 91 | bool aarch64; |
2ab37087 | 92 | bool thumb; |
e452ca5a | 93 | bool lse2; |
90e49638 PM |
94 | /* Because unallocated encodings generate different exception syndrome |
95 | * information from traps due to FP being disabled, we can't do a single | |
96 | * "is fp access disabled" check at a high level in the decode tree. | |
97 | * To help in catching bugs where the access check was forgotten in some | |
98 | * code path, we set this flag when the access check is done, and assert | |
99 | * that it is set at the point where we actually touch the FP regs. | |
100 | */ | |
101 | bool fp_access_checked; | |
8a40fe5f | 102 | bool sve_access_checked; |
7ea47fe7 PM |
103 | /* ARMv8 single-step state (this is distinct from the QEMU gdbstub |
104 | * single-step support). | |
105 | */ | |
106 | bool ss_active; | |
107 | bool pstate_ss; | |
108 | /* True if the insn just emitted was a load-exclusive instruction | |
109 | * (necessary for syndrome information for single step exceptions), | |
110 | * ie A64 LDX*, LDAX*, A32/T32 LDREX*, LDAEX*. | |
111 | */ | |
112 | bool is_ldex; | |
cc28fc30 RH |
113 | /* True if AccType_UNPRIV should be used for LDTR et al */ |
114 | bool unpriv; | |
0816ef1b RH |
115 | /* True if v8.3-PAuth is active. */ |
116 | bool pauth_active; | |
81ae05fa RH |
117 | /* True if v8.5-MTE access to tags is enabled. */ |
118 | bool ata; | |
119 | /* True if v8.5-MTE tag checks affect the PE; index with is_unpriv. */ | |
120 | bool mte_active[2]; | |
08f1434a RH |
121 | /* True with v8.5-BTI and SCTLR_ELx.BT* set. */ |
122 | bool bt; | |
5bb0a20b MZ |
123 | /* True if any CP15 access is trapped by HSTR_EL2 */ |
124 | bool hstr_active; | |
4479ec30 RH |
125 | /* True if memory operations require alignment */ |
126 | bool align_mem; | |
520d1621 PM |
127 | /* True if PSTATE.IL is set */ |
128 | bool pstate_il; | |
a3637e88 RH |
129 | /* True if PSTATE.SM is set. */ |
130 | bool pstate_sm; | |
131 | /* True if PSTATE.ZA is set. */ | |
132 | bool pstate_za; | |
75fe8356 RH |
133 | /* True if non-streaming insns should raise an SME Streaming exception. */ |
134 | bool sme_trap_nonstreaming; | |
135 | /* True if the current instruction is non-streaming. */ | |
136 | bool is_nonstreaming; | |
26702213 PM |
137 | /* True if MVE insns are definitely not predicated by VPR or LTPSIZE */ |
138 | bool mve_no_pred; | |
361c33f6 PM |
139 | /* True if fine-grained traps are active */ |
140 | bool fgt_active; | |
5572f755 PM |
141 | /* True if fine-grained trap on ERET is enabled */ |
142 | bool fgt_eret; | |
34a8a07e PM |
143 | /* True if fine-grained trap on SVC is enabled */ |
144 | bool fgt_svc; | |
51bf0d7a RH |
145 | /* |
146 | * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. | |
147 | * < 0, set by the current instruction. | |
148 | */ | |
149 | int8_t btype; | |
5f716a82 RH |
150 | /* A copy of cpu->dcz_blocksize. */ |
151 | uint8_t dcz_blocksize; | |
51bf0d7a RH |
152 | /* True if this page is guarded. */ |
153 | bool guarded_page; | |
c0f4af17 PM |
154 | /* Bottom two bits of XScale c15_cpar coprocessor access control reg */ |
155 | int c15_cpar; | |
15fa08f8 RH |
156 | /* TCG op of the current insn_start. */ |
157 | TCGOp *insn_start; | |
f570c61e AG |
158 | } DisasContext; |
159 | ||
6c2c63d3 RH |
160 | typedef struct DisasCompare { |
161 | TCGCond cond; | |
162 | TCGv_i32 value; | |
6c2c63d3 RH |
163 | } DisasCompare; |
164 | ||
78bcaa3e | 165 | /* Share the TCG temporaries common between 32 and 64 bit modes. */ |
78bcaa3e RH |
166 | extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF; |
167 | extern TCGv_i64 cpu_exclusive_addr; | |
168 | extern TCGv_i64 cpu_exclusive_val; | |
3407ad0e | 169 | |
b5aa6646 PM |
170 | /* |
171 | * Constant expanders for the decoders. | |
172 | */ | |
173 | ||
174 | static inline int negate(DisasContext *s, int x) | |
175 | { | |
176 | return -x; | |
177 | } | |
178 | ||
1d2386f7 PM |
179 | static inline int plus_1(DisasContext *s, int x) |
180 | { | |
181 | return x + 1; | |
182 | } | |
183 | ||
b5aa6646 PM |
184 | static inline int plus_2(DisasContext *s, int x) |
185 | { | |
186 | return x + 2; | |
187 | } | |
188 | ||
e9ad3ef1 RH |
189 | static inline int plus_12(DisasContext *s, int x) |
190 | { | |
191 | return x + 12; | |
192 | } | |
193 | ||
b5aa6646 PM |
194 | static inline int times_2(DisasContext *s, int x) |
195 | { | |
196 | return x * 2; | |
197 | } | |
198 | ||
199 | static inline int times_4(DisasContext *s, int x) | |
200 | { | |
201 | return x * 4; | |
202 | } | |
203 | ||
1d2386f7 PM |
204 | static inline int times_2_plus_1(DisasContext *s, int x) |
205 | { | |
206 | return x * 2 + 1; | |
207 | } | |
208 | ||
3394116f PM |
209 | static inline int rsub_64(DisasContext *s, int x) |
210 | { | |
211 | return 64 - x; | |
212 | } | |
213 | ||
214 | static inline int rsub_32(DisasContext *s, int x) | |
215 | { | |
216 | return 32 - x; | |
217 | } | |
218 | ||
219 | static inline int rsub_16(DisasContext *s, int x) | |
220 | { | |
221 | return 16 - x; | |
222 | } | |
223 | ||
224 | static inline int rsub_8(DisasContext *s, int x) | |
225 | { | |
226 | return 8 - x; | |
227 | } | |
228 | ||
3ce7b5ea RH |
229 | static inline int shl_12(DisasContext *s, int x) |
230 | { | |
231 | return x << 12; | |
232 | } | |
233 | ||
1e35cd91 PM |
234 | static inline int neon_3same_fp_size(DisasContext *s, int x) |
235 | { | |
236 | /* Convert 0==fp32, 1==fp16 into a MO_* value */ | |
237 | return MO_32 - x; | |
238 | } | |
239 | ||
a984e42c PM |
240 | static inline int arm_dc_feature(DisasContext *dc, int feature) |
241 | { | |
242 | return (dc->features & (1ULL << feature)) != 0; | |
243 | } | |
244 | ||
9d4c4e87 EI |
245 | static inline int get_mem_index(DisasContext *s) |
246 | { | |
8bd5c820 | 247 | return arm_to_core_mmu_idx(s->mmu_idx); |
9d4c4e87 EI |
248 | } |
249 | ||
cf96a682 | 250 | static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) |
9bb6558a PM |
251 | { |
252 | /* We don't need to save all of the syndrome so we mask and shift | |
253 | * out unneeded bits to help the sleb128 encoder do a better job. | |
254 | */ | |
255 | syn &= ARM_INSN_START_WORD2_MASK; | |
256 | syn >>= ARM_INSN_START_WORD2_SHIFT; | |
257 | ||
258 | /* We check and clear insn_start_idx to catch multiple updates. */ | |
15fa08f8 | 259 | assert(s->insn_start != NULL); |
9743cd57 | 260 | tcg_set_insn_start_param(s->insn_start, 2, syn); |
15fa08f8 | 261 | s->insn_start = NULL; |
9bb6558a PM |
262 | } |
263 | ||
8df87279 RH |
264 | static inline int curr_insn_len(DisasContext *s) |
265 | { | |
266 | return s->base.pc_next - s->pc_curr; | |
267 | } | |
268 | ||
77fc6f5e LV |
269 | /* is_jmp field values */ |
270 | #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ | |
14407ec2 RH |
271 | /* CPU state was modified dynamically; exit to main loop for interrupts. */ |
272 | #define DISAS_UPDATE_EXIT DISAS_TARGET_1 | |
40f860cd PM |
273 | /* These instructions trap after executing, so the A32/T32 decoder must |
274 | * defer them until after the conditional execution state has been updated. | |
275 | * WFI also needs special handling when single-stepping. | |
276 | */ | |
77fc6f5e LV |
277 | #define DISAS_WFI DISAS_TARGET_2 |
278 | #define DISAS_SWI DISAS_TARGET_3 | |
72c1d3af | 279 | /* WFE */ |
77fc6f5e LV |
280 | #define DISAS_WFE DISAS_TARGET_4 |
281 | #define DISAS_HVC DISAS_TARGET_5 | |
282 | #define DISAS_SMC DISAS_TARGET_6 | |
283 | #define DISAS_YIELD DISAS_TARGET_7 | |
3bb8a96f PM |
284 | /* M profile branch which might be an exception return (and so needs |
285 | * custom end-of-TB code) | |
286 | */ | |
77fc6f5e | 287 | #define DISAS_BX_EXCRET DISAS_TARGET_8 |
14407ec2 RH |
288 | /* |
289 | * For instructions which want an immediate exit to the main loop, as opposed | |
290 | * to attempting to use lookup_and_goto_ptr. Unlike DISAS_UPDATE_EXIT, this | |
291 | * doesn't write the PC on exiting the translation loop so you need to ensure | |
c44c8b8b | 292 | * something (gen_a64_update_pc or runtime helper) has done so before we reach |
14407ec2 | 293 | * return from cpu_tb_exec. |
8a6b28c7 | 294 | */ |
77fc6f5e | 295 | #define DISAS_EXIT DISAS_TARGET_9 |
32983328 RH |
296 | /* CPU state was modified dynamically; no need to exit, but do not chain. */ |
297 | #define DISAS_UPDATE_NOCHAIN DISAS_TARGET_10 | |
40f860cd | 298 | |
14ade10f AG |
299 | #ifdef TARGET_AARCH64 |
300 | void a64_translate_init(void); | |
c44c8b8b | 301 | void gen_a64_update_pc(DisasContext *s, target_long diff); |
23169224 | 302 | extern const TranslatorOps aarch64_translator_ops; |
14ade10f AG |
303 | #else |
304 | static inline void a64_translate_init(void) | |
305 | { | |
306 | } | |
307 | ||
c44c8b8b | 308 | static inline void gen_a64_update_pc(DisasContext *s, target_long diff) |
14ade10f AG |
309 | { |
310 | } | |
311 | #endif | |
312 | ||
6c2c63d3 | 313 | void arm_test_cc(DisasCompare *cmp, int cc); |
6c2c63d3 | 314 | void arm_jump_cc(DisasCompare *cmp, TCGLabel *label); |
42a268c2 | 315 | void arm_gen_test_cc(int cc, TCGLabel *label); |
a8502b37 | 316 | MemOp pow2_align(unsigned i); |
d9318a5f | 317 | void unallocated_encoding(DisasContext *s); |
55086e62 | 318 | void gen_exception_insn_el(DisasContext *s, target_long pc_diff, int excp, |
8c5d24dc | 319 | uint32_t syn, uint32_t target_el); |
55086e62 RH |
320 | void gen_exception_insn(DisasContext *s, target_long pc_diff, |
321 | int excp, uint32_t syn); | |
39fb730a | 322 | |
486624fc AB |
323 | /* Return state of Alternate Half-precision flag, caller frees result */ |
324 | static inline TCGv_i32 get_ahp_flag(void) | |
325 | { | |
326 | TCGv_i32 ret = tcg_temp_new_i32(); | |
327 | ||
328 | tcg_gen_ld_i32(ret, cpu_env, | |
329 | offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPSCR])); | |
330 | tcg_gen_extract_i32(ret, ret, 26, 1); | |
331 | ||
332 | return ret; | |
333 | } | |
334 | ||
22ac3c49 RH |
335 | /* Set bits within PSTATE. */ |
336 | static inline void set_pstate_bits(uint32_t bits) | |
337 | { | |
338 | TCGv_i32 p = tcg_temp_new_i32(); | |
339 | ||
340 | tcg_debug_assert(!(bits & CACHED_PSTATE_BITS)); | |
341 | ||
342 | tcg_gen_ld_i32(p, cpu_env, offsetof(CPUARMState, pstate)); | |
343 | tcg_gen_ori_i32(p, p, bits); | |
344 | tcg_gen_st_i32(p, cpu_env, offsetof(CPUARMState, pstate)); | |
22ac3c49 RH |
345 | } |
346 | ||
347 | /* Clear bits within PSTATE. */ | |
348 | static inline void clear_pstate_bits(uint32_t bits) | |
349 | { | |
350 | TCGv_i32 p = tcg_temp_new_i32(); | |
351 | ||
352 | tcg_debug_assert(!(bits & CACHED_PSTATE_BITS)); | |
353 | ||
354 | tcg_gen_ld_i32(p, cpu_env, offsetof(CPUARMState, pstate)); | |
355 | tcg_gen_andi_i32(p, p, ~bits); | |
356 | tcg_gen_st_i32(p, cpu_env, offsetof(CPUARMState, pstate)); | |
22ac3c49 RH |
357 | } |
358 | ||
359 | /* If the singlestep state is Active-not-pending, advance to Active-pending. */ | |
360 | static inline void gen_ss_advance(DisasContext *s) | |
361 | { | |
362 | if (s->ss_active) { | |
363 | s->pstate_ss = 0; | |
364 | clear_pstate_bits(PSTATE_SS); | |
365 | } | |
366 | } | |
eabcd6fa | 367 | |
c1d5f50f PM |
368 | /* Generate an architectural singlestep exception */ |
369 | static inline void gen_swstep_exception(DisasContext *s, int isv, int ex) | |
370 | { | |
f0d7c205 RH |
371 | /* Fill in the same_el field of the syndrome in the helper. */ |
372 | uint32_t syn = syn_swstep(false, isv, ex); | |
373 | gen_helper_exception_swstep(cpu_env, tcg_constant_i32(syn)); | |
c1d5f50f PM |
374 | } |
375 | ||
d6a092d4 PM |
376 | /* |
377 | * Given a VFP floating point constant encoded into an 8 bit immediate in an | |
378 | * instruction, expand it to the actual constant value of the specified | |
379 | * size, as per the VFPExpandImm() pseudocode in the Arm ARM. | |
380 | */ | |
381 | uint64_t vfp_expand_imm(int size, uint8_t imm8); | |
382 | ||
eabcd6fa | 383 | /* Vector operations shared between ARM and AArch64. */ |
69d5e2bf RH |
384 | void gen_gvec_ceq0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, |
385 | uint32_t opr_sz, uint32_t max_sz); | |
386 | void gen_gvec_clt0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, | |
387 | uint32_t opr_sz, uint32_t max_sz); | |
388 | void gen_gvec_cgt0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, | |
389 | uint32_t opr_sz, uint32_t max_sz); | |
390 | void gen_gvec_cle0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, | |
391 | uint32_t opr_sz, uint32_t max_sz); | |
392 | void gen_gvec_cge0(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, | |
393 | uint32_t opr_sz, uint32_t max_sz); | |
394 | ||
27106320 RH |
395 | void gen_gvec_mla(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, |
396 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
397 | void gen_gvec_mls(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, | |
398 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
399 | ||
8161b753 RH |
400 | void gen_gvec_cmtst(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, |
401 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
402 | void gen_gvec_sshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, | |
403 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
404 | void gen_gvec_ushl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, | |
405 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
406 | ||
ea580fa3 | 407 | void gen_cmtst_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b); |
87b74e8b RH |
408 | void gen_ushl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b); |
409 | void gen_sshl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b); | |
410 | void gen_ushl_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b); | |
411 | void gen_sshl_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b); | |
eabcd6fa | 412 | |
c7715b6b RH |
413 | void gen_gvec_uqadd_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, |
414 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
415 | void gen_gvec_sqadd_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, | |
416 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
417 | void gen_gvec_uqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, | |
418 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
419 | void gen_gvec_sqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, | |
420 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
421 | ||
631e5654 RH |
422 | void gen_gvec_ssra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, |
423 | int64_t shift, uint32_t opr_sz, uint32_t max_sz); | |
424 | void gen_gvec_usra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, | |
425 | int64_t shift, uint32_t opr_sz, uint32_t max_sz); | |
426 | ||
6ccd48d4 RH |
427 | void gen_gvec_srshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, |
428 | int64_t shift, uint32_t opr_sz, uint32_t max_sz); | |
429 | void gen_gvec_urshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, | |
430 | int64_t shift, uint32_t opr_sz, uint32_t max_sz); | |
431 | void gen_gvec_srsra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, | |
432 | int64_t shift, uint32_t opr_sz, uint32_t max_sz); | |
433 | void gen_gvec_ursra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, | |
434 | int64_t shift, uint32_t opr_sz, uint32_t max_sz); | |
435 | ||
893ab054 RH |
436 | void gen_gvec_sri(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, |
437 | int64_t shift, uint32_t opr_sz, uint32_t max_sz); | |
438 | void gen_gvec_sli(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs, | |
439 | int64_t shift, uint32_t opr_sz, uint32_t max_sz); | |
440 | ||
146aa66c RH |
441 | void gen_gvec_sqrdmlah_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, |
442 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
443 | void gen_gvec_sqrdmlsh_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, | |
444 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
445 | ||
50c160d4 RH |
446 | void gen_gvec_sabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, |
447 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
448 | void gen_gvec_uabd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, | |
449 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
450 | ||
cfdb2c0c RH |
451 | void gen_gvec_saba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, |
452 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
453 | void gen_gvec_uaba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, | |
454 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
455 | ||
962fcbf2 RH |
456 | /* |
457 | * Forward to the isar_feature_* tests given a DisasContext pointer. | |
458 | */ | |
459 | #define dc_isar_feature(name, ctx) \ | |
460 | ({ DisasContext *ctx_ = (ctx); isar_feature_##name(ctx_->isar); }) | |
461 | ||
a4e143ac PM |
462 | /* Note that the gvec expanders operate on offsets + sizes. */ |
463 | typedef void GVecGen2Fn(unsigned, uint32_t, uint32_t, uint32_t, uint32_t); | |
464 | typedef void GVecGen2iFn(unsigned, uint32_t, uint32_t, int64_t, | |
465 | uint32_t, uint32_t); | |
466 | typedef void GVecGen3Fn(unsigned, uint32_t, uint32_t, | |
467 | uint32_t, uint32_t, uint32_t); | |
468 | typedef void GVecGen4Fn(unsigned, uint32_t, uint32_t, uint32_t, | |
469 | uint32_t, uint32_t, uint32_t); | |
470 | ||
9aefc6cf | 471 | /* Function prototype for gen_ functions for calling Neon helpers */ |
89668082 | 472 | typedef void NeonGenOneOpFn(TCGv_i32, TCGv_i32); |
9aefc6cf PM |
473 | typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32); |
474 | typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32); | |
475 | typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32); | |
9194a9cb PM |
476 | typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32, |
477 | TCGv_i32, TCGv_i32); | |
9aefc6cf PM |
478 | typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64); |
479 | typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64); | |
480 | typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); | |
481 | typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64); | |
482 | typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); | |
f5b28401 | 483 | typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32); |
3e96b205 | 484 | typedef void NeonGenOneSingleOpFn(TCGv_i32, TCGv_i32, TCGv_ptr); |
5de3fd04 PM |
485 | typedef void NeonGenTwoSingleOpFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); |
486 | typedef void NeonGenTwoDoubleOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); | |
039f4e80 | 487 | typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64); |
9aefc6cf PM |
488 | typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr); |
489 | typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32); | |
490 | typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); | |
491 | typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, MemOp); | |
f4ae6c8c | 492 | typedef void WideShiftImmFn(TCGv_i64, TCGv_i64, int64_t shift); |
0aa4b4c3 | 493 | typedef void WideShiftFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i32); |
46321d47 | 494 | typedef void ShiftImmFn(TCGv_i32, TCGv_i32, int32_t shift); |
04ea4d3c | 495 | typedef void ShiftFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32); |
9aefc6cf | 496 | |
3902bfc6 RH |
497 | /** |
498 | * arm_tbflags_from_tb: | |
499 | * @tb: the TranslationBlock | |
500 | * | |
501 | * Extract the flag values from @tb. | |
502 | */ | |
503 | static inline CPUARMTBFlags arm_tbflags_from_tb(const TranslationBlock *tb) | |
504 | { | |
a378206a | 505 | return (CPUARMTBFlags){ tb->flags, tb->cs_base }; |
3902bfc6 RH |
506 | } |
507 | ||
cdfb22bb PM |
508 | /* |
509 | * Enum for argument to fpstatus_ptr(). | |
510 | */ | |
511 | typedef enum ARMFPStatusFlavour { | |
512 | FPST_FPCR, | |
513 | FPST_FPCR_F16, | |
514 | FPST_STD, | |
515 | FPST_STD_F16, | |
516 | } ARMFPStatusFlavour; | |
517 | ||
518 | /** | |
519 | * fpstatus_ptr: return TCGv_ptr to the specified fp_status field | |
520 | * | |
521 | * We have multiple softfloat float_status fields in the Arm CPU state struct | |
522 | * (see the comment in cpu.h for details). Return a TCGv_ptr which has | |
523 | * been set up to point to the requested field in the CPU state struct. | |
524 | * The options are: | |
525 | * | |
526 | * FPST_FPCR | |
527 | * for non-FP16 operations controlled by the FPCR | |
528 | * FPST_FPCR_F16 | |
529 | * for operations controlled by the FPCR where FPCR.FZ16 is to be used | |
530 | * FPST_STD | |
531 | * for A32/T32 Neon operations using the "standard FPSCR value" | |
532 | * FPST_STD_F16 | |
533 | * as FPST_STD, but where FPCR.FZ16 is to be used | |
534 | */ | |
535 | static inline TCGv_ptr fpstatus_ptr(ARMFPStatusFlavour flavour) | |
536 | { | |
537 | TCGv_ptr statusptr = tcg_temp_new_ptr(); | |
538 | int offset; | |
539 | ||
540 | switch (flavour) { | |
541 | case FPST_FPCR: | |
542 | offset = offsetof(CPUARMState, vfp.fp_status); | |
543 | break; | |
544 | case FPST_FPCR_F16: | |
545 | offset = offsetof(CPUARMState, vfp.fp_status_f16); | |
546 | break; | |
547 | case FPST_STD: | |
548 | offset = offsetof(CPUARMState, vfp.standard_fp_status); | |
549 | break; | |
550 | case FPST_STD_F16: | |
aaae563b PM |
551 | offset = offsetof(CPUARMState, vfp.standard_fp_status_f16); |
552 | break; | |
cdfb22bb PM |
553 | default: |
554 | g_assert_not_reached(); | |
555 | } | |
556 | tcg_gen_addi_ptr(statusptr, cpu_env, offset); | |
557 | return statusptr; | |
558 | } | |
559 | ||
9d486b40 | 560 | /** |
e452ca5a | 561 | * finalize_memop_atom: |
9d486b40 RH |
562 | * @s: DisasContext |
563 | * @opc: size+sign+align of the memory operation | |
e452ca5a | 564 | * @atom: atomicity of the memory operation |
9d486b40 | 565 | * |
e452ca5a RH |
566 | * Build the complete MemOp for a memory operation, including alignment, |
567 | * endianness, and atomicity. | |
9d486b40 RH |
568 | * |
569 | * If (op & MO_AMASK) then the operation already contains the required | |
570 | * alignment, e.g. for AccType_ATOMIC. Otherwise, this an optionally | |
571 | * unaligned operation, e.g. for AccType_NORMAL. | |
572 | * | |
573 | * In the latter case, there are configuration bits that require alignment, | |
574 | * and this is applied here. Note that there is no way to indicate that | |
575 | * no alignment should ever be enforced; this must be handled manually. | |
576 | */ | |
e452ca5a | 577 | static inline MemOp finalize_memop_atom(DisasContext *s, MemOp opc, MemOp atom) |
9d486b40 RH |
578 | { |
579 | if (s->align_mem && !(opc & MO_AMASK)) { | |
580 | opc |= MO_ALIGN; | |
581 | } | |
e452ca5a RH |
582 | return opc | atom | s->be_data; |
583 | } | |
584 | ||
585 | /** | |
586 | * finalize_memop: | |
587 | * @s: DisasContext | |
588 | * @opc: size+sign+align of the memory operation | |
589 | * | |
590 | * Like finalize_memop_atom, but with default atomicity. | |
591 | */ | |
592 | static inline MemOp finalize_memop(DisasContext *s, MemOp opc) | |
593 | { | |
594 | MemOp atom = s->lse2 ? MO_ATOM_WITHIN16 : MO_ATOM_IFALIGN; | |
595 | return finalize_memop_atom(s, opc, atom); | |
596 | } | |
597 | ||
598 | /** | |
599 | * finalize_memop_pair: | |
600 | * @s: DisasContext | |
601 | * @opc: size+sign+align of the memory operation | |
602 | * | |
603 | * Like finalize_memop_atom, but with atomicity for a pair. | |
604 | * C.f. Pseudocode for Mem[], operand ispair. | |
605 | */ | |
606 | static inline MemOp finalize_memop_pair(DisasContext *s, MemOp opc) | |
607 | { | |
608 | MemOp atom = s->lse2 ? MO_ATOM_WITHIN16_PAIR : MO_ATOM_IFALIGN_PAIR; | |
609 | return finalize_memop_atom(s, opc, atom); | |
9d486b40 RH |
610 | } |
611 | ||
dfd66bc0 PM |
612 | /** |
613 | * asimd_imm_const: Expand an encoded SIMD constant value | |
614 | * | |
615 | * Expand a SIMD constant value. This is essentially the pseudocode | |
616 | * AdvSIMDExpandImm, except that we also perform the boolean NOT needed for | |
617 | * VMVN and VBIC (when cmode < 14 && op == 1). | |
618 | * | |
619 | * The combination cmode == 15 op == 1 is a reserved encoding for AArch32; | |
2c0286db PM |
620 | * callers must catch this; we return the 64-bit constant value defined |
621 | * for AArch64. | |
dfd66bc0 PM |
622 | * |
623 | * cmode = 2,3,4,5,6,7,10,11,12,13 imm=0 was UNPREDICTABLE in v7A but | |
624 | * is either not unpredictable or merely CONSTRAINED UNPREDICTABLE in v8A; | |
625 | * we produce an immediate constant value of 0 in these cases. | |
626 | */ | |
627 | uint64_t asimd_imm_const(uint32_t imm, int cmode, int op); | |
628 | ||
abb80995 RH |
629 | /* |
630 | * gen_disas_label: | |
631 | * Create a label and cache a copy of pc_save. | |
632 | */ | |
633 | static inline DisasLabel gen_disas_label(DisasContext *s) | |
634 | { | |
635 | return (DisasLabel){ | |
636 | .label = gen_new_label(), | |
637 | .pc_save = s->pc_save, | |
638 | }; | |
639 | } | |
640 | ||
641 | /* | |
642 | * set_disas_label: | |
643 | * Emit a label and restore the cached copy of pc_save. | |
644 | */ | |
645 | static inline void set_disas_label(DisasContext *s, DisasLabel l) | |
646 | { | |
647 | gen_set_label(l.label); | |
648 | s->pc_save = l.pc_save; | |
649 | } | |
650 | ||
3b07a936 RH |
651 | static inline TCGv_ptr gen_lookup_cp_reg(uint32_t key) |
652 | { | |
653 | TCGv_ptr ret = tcg_temp_new_ptr(); | |
654 | gen_helper_lookup_cp_reg(ret, cpu_env, tcg_constant_i32(key)); | |
655 | return ret; | |
656 | } | |
657 | ||
8d1b02a6 RH |
658 | /* |
659 | * Set and reset rounding mode around another operation. | |
660 | */ | |
661 | static inline TCGv_i32 gen_set_rmode(ARMFPRounding rmode, TCGv_ptr fpst) | |
662 | { | |
663 | TCGv_i32 new = tcg_constant_i32(arm_rmode_to_sf(rmode)); | |
664 | TCGv_i32 old = tcg_temp_new_i32(); | |
665 | ||
666 | gen_helper_set_rmode(old, new, fpst); | |
667 | return old; | |
668 | } | |
669 | ||
670 | static inline void gen_restore_rmode(TCGv_i32 old, TCGv_ptr fpst) | |
671 | { | |
672 | gen_helper_set_rmode(old, old, fpst); | |
673 | } | |
674 | ||
05a54642 RH |
675 | /* |
676 | * Helpers for implementing sets of trans_* functions. | |
677 | * Defer the implementation of NAME to FUNC, with optional extra arguments. | |
678 | */ | |
679 | #define TRANS(NAME, FUNC, ...) \ | |
680 | static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ | |
681 | { return FUNC(s, __VA_ARGS__); } | |
682 | #define TRANS_FEAT(NAME, FEAT, FUNC, ...) \ | |
683 | static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ | |
684 | { return dc_isar_feature(FEAT, s) && FUNC(s, __VA_ARGS__); } | |
685 | ||
7160c8c5 RH |
686 | #define TRANS_FEAT_NONSTREAMING(NAME, FEAT, FUNC, ...) \ |
687 | static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ | |
688 | { \ | |
689 | s->is_nonstreaming = true; \ | |
690 | return dc_isar_feature(FEAT, s) && FUNC(s, __VA_ARGS__); \ | |
691 | } | |
692 | ||
f570c61e | 693 | #endif /* TARGET_ARM_TRANSLATE_H */ |