]>
Commit | Line | Data |
---|---|---|
8c71baed RH |
1 | /* |
2 | * AArch64 translation, common definitions. | |
3 | * | |
4 | * This library is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU Lesser General Public | |
6 | * License as published by the Free Software Foundation; either | |
50f57e09 | 7 | * version 2.1 of the License, or (at your option) any later version. |
8c71baed RH |
8 | * |
9 | * This library is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | * Lesser General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU Lesser General Public | |
15 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
17 | ||
18 | #ifndef TARGET_ARM_TRANSLATE_A64_H | |
19 | #define TARGET_ARM_TRANSLATE_A64_H | |
20 | ||
8c71baed | 21 | TCGv_i64 new_tmp_a64(DisasContext *s); |
4b4dc975 | 22 | TCGv_i64 new_tmp_a64_local(DisasContext *s); |
8c71baed RH |
23 | TCGv_i64 new_tmp_a64_zero(DisasContext *s); |
24 | TCGv_i64 cpu_reg(DisasContext *s, int reg); | |
25 | TCGv_i64 cpu_reg_sp(DisasContext *s, int reg); | |
26 | TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf); | |
27 | TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf); | |
28 | void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v); | |
8c71baed RH |
29 | bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn, |
30 | unsigned int imms, unsigned int immr); | |
8c71baed | 31 | bool sve_access_check(DisasContext *s); |
3d74825f RH |
32 | bool sme_enabled_check(DisasContext *s); |
33 | bool sme_enabled_check_with_svcr(DisasContext *s, unsigned); | |
34 | ||
35 | /* This function corresponds to CheckStreamingSVEEnabled. */ | |
36 | static inline bool sme_sm_enabled_check(DisasContext *s) | |
37 | { | |
38 | return sme_enabled_check_with_svcr(s, R_SVCR_SM_MASK); | |
39 | } | |
40 | ||
41 | /* This function corresponds to CheckSMEAndZAEnabled. */ | |
42 | static inline bool sme_za_enabled_check(DisasContext *s) | |
43 | { | |
44 | return sme_enabled_check_with_svcr(s, R_SVCR_ZA_MASK); | |
45 | } | |
46 | ||
47 | /* Note that this function corresponds to CheckStreamingSVEAndZAEnabled. */ | |
48 | static inline bool sme_smza_enabled_check(DisasContext *s) | |
49 | { | |
50 | return sme_enabled_check_with_svcr(s, R_SVCR_SM_MASK | R_SVCR_ZA_MASK); | |
51 | } | |
52 | ||
9473d0ec | 53 | TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr); |
0a405be2 RH |
54 | TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write, |
55 | bool tag_checked, int log2_size); | |
73ceeb00 | 56 | TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, |
33e74c31 | 57 | bool tag_checked, int size); |
8c71baed RH |
58 | |
59 | /* We should have at some point before trying to access an FP register | |
60 | * done the necessary access check, so assert that | |
61 | * (a) we did the check and | |
62 | * (b) we didn't then just plough ahead anyway if it failed. | |
63 | * Print the instruction pattern in the abort message so we can figure | |
64 | * out what we need to fix if a user encounters this problem in the wild. | |
65 | */ | |
66 | static inline void assert_fp_access_checked(DisasContext *s) | |
67 | { | |
68 | #ifdef CONFIG_DEBUG_TCG | |
69 | if (unlikely(!s->fp_access_checked || s->fp_excp_el)) { | |
70 | fprintf(stderr, "target-arm: FP access check missing for " | |
71 | "instruction 0x%08x\n", s->insn); | |
72 | abort(); | |
73 | } | |
74 | #endif | |
75 | } | |
76 | ||
77 | /* Return the offset into CPUARMState of an element of specified | |
78 | * size, 'element' places in from the least significant end of | |
79 | * the FP/vector register Qn. | |
80 | */ | |
81 | static inline int vec_reg_offset(DisasContext *s, int regno, | |
14776ab5 | 82 | int element, MemOp size) |
8c71baed | 83 | { |
66f2dbd7 RH |
84 | int element_size = 1 << size; |
85 | int offs = element * element_size; | |
e03b5686 | 86 | #if HOST_BIG_ENDIAN |
8c71baed | 87 | /* This is complicated slightly because vfp.zregs[n].d[0] is |
66f2dbd7 RH |
88 | * still the lowest and vfp.zregs[n].d[15] the highest of the |
89 | * 256 byte vector, even on big endian systems. | |
90 | * | |
91 | * Calculate the offset assuming fully little-endian, | |
92 | * then XOR to account for the order of the 8-byte units. | |
93 | * | |
94 | * For 16 byte elements, the two 8 byte halves will not form a | |
95 | * host int128 if the host is bigendian, since they're in the | |
96 | * wrong order. However the only 16 byte operation we have is | |
97 | * a move, so we can ignore this for the moment. More complicated | |
98 | * operations will have to special case loading and storing from | |
99 | * the zregs array. | |
8c71baed | 100 | */ |
66f2dbd7 RH |
101 | if (element_size < 8) { |
102 | offs ^= 8 - element_size; | |
103 | } | |
8c71baed RH |
104 | #endif |
105 | offs += offsetof(CPUARMState, vfp.zregs[regno]); | |
106 | assert_fp_access_checked(s); | |
107 | return offs; | |
108 | } | |
109 | ||
110 | /* Return the offset info CPUARMState of the "whole" vector register Qn. */ | |
111 | static inline int vec_full_reg_offset(DisasContext *s, int regno) | |
112 | { | |
113 | assert_fp_access_checked(s); | |
114 | return offsetof(CPUARMState, vfp.zregs[regno]); | |
115 | } | |
116 | ||
117 | /* Return a newly allocated pointer to the vector register. */ | |
118 | static inline TCGv_ptr vec_full_reg_ptr(DisasContext *s, int regno) | |
119 | { | |
120 | TCGv_ptr ret = tcg_temp_new_ptr(); | |
121 | tcg_gen_addi_ptr(ret, cpu_env, vec_full_reg_offset(s, regno)); | |
122 | return ret; | |
123 | } | |
124 | ||
125 | /* Return the byte size of the "whole" vector register, VL / 8. */ | |
126 | static inline int vec_full_reg_size(DisasContext *s) | |
127 | { | |
f45ce4c3 | 128 | return s->vl; |
8c71baed RH |
129 | } |
130 | ||
0d935760 RH |
131 | /* Return the byte size of the vector register, SVL / 8. */ |
132 | static inline int streaming_vec_reg_size(DisasContext *s) | |
133 | { | |
134 | return s->svl; | |
135 | } | |
136 | ||
d61d1b86 RH |
137 | /* |
138 | * Return the offset info CPUARMState of the predicate vector register Pn. | |
139 | * Note for this purpose, FFR is P16. | |
140 | */ | |
141 | static inline int pred_full_reg_offset(DisasContext *s, int regno) | |
142 | { | |
143 | return offsetof(CPUARMState, vfp.pregs[regno]); | |
144 | } | |
145 | ||
146 | /* Return the byte size of the whole predicate register, VL / 64. */ | |
147 | static inline int pred_full_reg_size(DisasContext *s) | |
148 | { | |
149 | return s->vl >> 3; | |
150 | } | |
151 | ||
0d935760 RH |
152 | /* Return the byte size of the predicate register, SVL / 64. */ |
153 | static inline int streaming_pred_reg_size(DisasContext *s) | |
154 | { | |
155 | return s->svl >> 3; | |
156 | } | |
157 | ||
d61d1b86 RH |
158 | /* |
159 | * Round up the size of a register to a size allowed by | |
160 | * the tcg vector infrastructure. Any operation which uses this | |
161 | * size may assume that the bits above pred_full_reg_size are zero, | |
162 | * and must leave them the same way. | |
163 | * | |
164 | * Note that this is not needed for the vector registers as they | |
165 | * are always properly sized for tcg vectors. | |
166 | */ | |
167 | static inline int size_for_gvec(int size) | |
168 | { | |
169 | if (size <= 8) { | |
170 | return 8; | |
171 | } else { | |
172 | return QEMU_ALIGN_UP(size, 16); | |
173 | } | |
174 | } | |
175 | ||
176 | static inline int pred_gvec_reg_size(DisasContext *s) | |
177 | { | |
178 | return size_for_gvec(pred_full_reg_size(s)); | |
179 | } | |
180 | ||
e9ad3ef1 RH |
181 | /* Return a newly allocated pointer to the predicate register. */ |
182 | static inline TCGv_ptr pred_full_reg_ptr(DisasContext *s, int regno) | |
183 | { | |
184 | TCGv_ptr ret = tcg_temp_new_ptr(); | |
185 | tcg_gen_addi_ptr(ret, cpu_env, pred_full_reg_offset(s, regno)); | |
186 | return ret; | |
187 | } | |
188 | ||
8c71baed | 189 | bool disas_sve(DisasContext *, uint32_t); |
e67cd1ca | 190 | bool disas_sme(DisasContext *, uint32_t); |
8c71baed | 191 | |
1738860d RH |
192 | void gen_gvec_rax1(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, |
193 | uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz); | |
e6eba6e5 RH |
194 | void gen_gvec_xar(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, |
195 | uint32_t rm_ofs, int64_t shift, | |
196 | uint32_t opr_sz, uint32_t max_sz); | |
1738860d | 197 | |
8c71baed | 198 | #endif /* TARGET_ARM_TRANSLATE_A64_H */ |