1f0984d40SFabiano Rosas /*
2f0984d40SFabiano Rosas * ARM translation: M-profile NOCP special-case instructions
3f0984d40SFabiano Rosas *
4f0984d40SFabiano Rosas * Copyright (c) 2020 Linaro, Ltd.
5f0984d40SFabiano Rosas *
6f0984d40SFabiano Rosas * This library is free software; you can redistribute it and/or
7f0984d40SFabiano Rosas * modify it under the terms of the GNU Lesser General Public
8f0984d40SFabiano Rosas * License as published by the Free Software Foundation; either
9f0984d40SFabiano Rosas * version 2.1 of the License, or (at your option) any later version.
10f0984d40SFabiano Rosas *
11f0984d40SFabiano Rosas * This library is distributed in the hope that it will be useful,
12f0984d40SFabiano Rosas * but WITHOUT ANY WARRANTY; without even the implied warranty of
13f0984d40SFabiano Rosas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14f0984d40SFabiano Rosas * Lesser General Public License for more details.
15f0984d40SFabiano Rosas *
16f0984d40SFabiano Rosas * You should have received a copy of the GNU Lesser General Public
17f0984d40SFabiano Rosas * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18f0984d40SFabiano Rosas */
19f0984d40SFabiano Rosas
20f0984d40SFabiano Rosas #include "qemu/osdep.h"
21f0984d40SFabiano Rosas #include "translate.h"
22f0984d40SFabiano Rosas #include "translate-a32.h"
23f0984d40SFabiano Rosas
24f0984d40SFabiano Rosas #include "decode-m-nocp.c.inc"
25f0984d40SFabiano Rosas
26f0984d40SFabiano Rosas /*
27f0984d40SFabiano Rosas * Decode VLLDM and VLSTM are nonstandard because:
28f0984d40SFabiano Rosas * * if there is no FPU then these insns must NOP in
29f0984d40SFabiano Rosas * Secure state and UNDEF in Nonsecure state
30f0984d40SFabiano Rosas * * if there is an FPU then these insns do not have
31f0984d40SFabiano Rosas * the usual behaviour that vfp_access_check() provides of
32f0984d40SFabiano Rosas * being controlled by CPACR/NSACR enable bits or the
33f0984d40SFabiano Rosas * lazy-stacking logic.
34f0984d40SFabiano Rosas */
trans_VLLDM_VLSTM(DisasContext * s,arg_VLLDM_VLSTM * a)35f0984d40SFabiano Rosas static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
36f0984d40SFabiano Rosas {
37f0984d40SFabiano Rosas TCGv_i32 fptr;
38f0984d40SFabiano Rosas
39f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_M) ||
40f0984d40SFabiano Rosas !arm_dc_feature(s, ARM_FEATURE_V8)) {
41f0984d40SFabiano Rosas return false;
42f0984d40SFabiano Rosas }
43f0984d40SFabiano Rosas
44f0984d40SFabiano Rosas if (a->op) {
45f0984d40SFabiano Rosas /*
46f0984d40SFabiano Rosas * T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not
47f0984d40SFabiano Rosas * to take the IMPDEF option to make memory accesses to the stack
48f0984d40SFabiano Rosas * slots that correspond to the D16-D31 registers (discarding
49f0984d40SFabiano Rosas * read data and writing UNKNOWN values), so for us the T2
50f0984d40SFabiano Rosas * encoding behaves identically to the T1 encoding.
51f0984d40SFabiano Rosas */
52f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
53f0984d40SFabiano Rosas return false;
54f0984d40SFabiano Rosas }
55f0984d40SFabiano Rosas } else {
56f0984d40SFabiano Rosas /*
57f0984d40SFabiano Rosas * T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs.
58f0984d40SFabiano Rosas * This is currently architecturally impossible, but we add the
59f0984d40SFabiano Rosas * check to stay in line with the pseudocode. Note that we must
60f0984d40SFabiano Rosas * emit code for the UNDEF so it takes precedence over the NOCP.
61f0984d40SFabiano Rosas */
62f0984d40SFabiano Rosas if (dc_isar_feature(aa32_simd_r32, s)) {
63f0984d40SFabiano Rosas unallocated_encoding(s);
64f0984d40SFabiano Rosas return true;
65f0984d40SFabiano Rosas }
66f0984d40SFabiano Rosas }
67f0984d40SFabiano Rosas
68f0984d40SFabiano Rosas /*
69f0984d40SFabiano Rosas * If not secure, UNDEF. We must emit code for this
70f0984d40SFabiano Rosas * rather than returning false so that this takes
71f0984d40SFabiano Rosas * precedence over the m-nocp.decode NOCP fallback.
72f0984d40SFabiano Rosas */
73f0984d40SFabiano Rosas if (!s->v8m_secure) {
74f0984d40SFabiano Rosas unallocated_encoding(s);
75f0984d40SFabiano Rosas return true;
76f0984d40SFabiano Rosas }
77f0984d40SFabiano Rosas
78f0984d40SFabiano Rosas s->eci_handled = true;
79f0984d40SFabiano Rosas
80f0984d40SFabiano Rosas /* If no fpu, NOP. */
81f0984d40SFabiano Rosas if (!dc_isar_feature(aa32_vfp, s)) {
82f0984d40SFabiano Rosas clear_eci_state(s);
83f0984d40SFabiano Rosas return true;
84f0984d40SFabiano Rosas }
85f0984d40SFabiano Rosas
86f0984d40SFabiano Rosas fptr = load_reg(s, a->rn);
87f0984d40SFabiano Rosas if (a->l) {
88ad75a51eSRichard Henderson gen_helper_v7m_vlldm(tcg_env, fptr);
89f0984d40SFabiano Rosas } else {
90ad75a51eSRichard Henderson gen_helper_v7m_vlstm(tcg_env, fptr);
91f0984d40SFabiano Rosas }
92f0984d40SFabiano Rosas
93f0984d40SFabiano Rosas clear_eci_state(s);
94f0984d40SFabiano Rosas
95f0984d40SFabiano Rosas /*
96f0984d40SFabiano Rosas * End the TB, because we have updated FP control bits,
97f0984d40SFabiano Rosas * and possibly VPR or LTPSIZE.
98f0984d40SFabiano Rosas */
99f0984d40SFabiano Rosas s->base.is_jmp = DISAS_UPDATE_EXIT;
100f0984d40SFabiano Rosas return true;
101f0984d40SFabiano Rosas }
102f0984d40SFabiano Rosas
trans_VSCCLRM(DisasContext * s,arg_VSCCLRM * a)103f0984d40SFabiano Rosas static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a)
104f0984d40SFabiano Rosas {
105f0984d40SFabiano Rosas int btmreg, topreg;
106f0984d40SFabiano Rosas TCGv_i64 zero;
107f0984d40SFabiano Rosas TCGv_i32 aspen, sfpa;
108f0984d40SFabiano Rosas
109f0984d40SFabiano Rosas if (!dc_isar_feature(aa32_m_sec_state, s)) {
110f0984d40SFabiano Rosas /* Before v8.1M, fall through in decode to NOCP check */
111f0984d40SFabiano Rosas return false;
112f0984d40SFabiano Rosas }
113f0984d40SFabiano Rosas
114f0984d40SFabiano Rosas /* Explicitly UNDEF because this takes precedence over NOCP */
115f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) {
116f0984d40SFabiano Rosas unallocated_encoding(s);
117f0984d40SFabiano Rosas return true;
118f0984d40SFabiano Rosas }
119f0984d40SFabiano Rosas
120f0984d40SFabiano Rosas s->eci_handled = true;
121f0984d40SFabiano Rosas
122f0984d40SFabiano Rosas if (!dc_isar_feature(aa32_vfp_simd, s)) {
123f0984d40SFabiano Rosas /* NOP if we have neither FP nor MVE */
124f0984d40SFabiano Rosas clear_eci_state(s);
125f0984d40SFabiano Rosas return true;
126f0984d40SFabiano Rosas }
127f0984d40SFabiano Rosas
128f0984d40SFabiano Rosas /*
129f0984d40SFabiano Rosas * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no
130f0984d40SFabiano Rosas * active floating point context so we must NOP (without doing
131f0984d40SFabiano Rosas * any lazy state preservation or the NOCP check).
132f0984d40SFabiano Rosas */
133f0984d40SFabiano Rosas aspen = load_cpu_field(v7m.fpccr[M_REG_S]);
134f0984d40SFabiano Rosas sfpa = load_cpu_field(v7m.control[M_REG_S]);
135f0984d40SFabiano Rosas tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
136f0984d40SFabiano Rosas tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
137f0984d40SFabiano Rosas tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK);
138f0984d40SFabiano Rosas tcg_gen_or_i32(sfpa, sfpa, aspen);
139f0984d40SFabiano Rosas arm_gen_condlabel(s);
140f0984d40SFabiano Rosas tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel.label);
141f0984d40SFabiano Rosas
142f0984d40SFabiano Rosas if (s->fp_excp_el != 0) {
143f0984d40SFabiano Rosas gen_exception_insn_el(s, 0, EXCP_NOCP,
144f0984d40SFabiano Rosas syn_uncategorized(), s->fp_excp_el);
145f0984d40SFabiano Rosas return true;
146f0984d40SFabiano Rosas }
147f0984d40SFabiano Rosas
148f0984d40SFabiano Rosas topreg = a->vd + a->imm - 1;
149f0984d40SFabiano Rosas btmreg = a->vd;
150f0984d40SFabiano Rosas
151f0984d40SFabiano Rosas /* Convert to Sreg numbers if the insn specified in Dregs */
152f0984d40SFabiano Rosas if (a->size == 3) {
153f0984d40SFabiano Rosas topreg = topreg * 2 + 1;
154f0984d40SFabiano Rosas btmreg *= 2;
155f0984d40SFabiano Rosas }
156f0984d40SFabiano Rosas
157f0984d40SFabiano Rosas if (topreg > 63 || (topreg > 31 && !(topreg & 1))) {
158f0984d40SFabiano Rosas /* UNPREDICTABLE: we choose to undef */
159f0984d40SFabiano Rosas unallocated_encoding(s);
160f0984d40SFabiano Rosas return true;
161f0984d40SFabiano Rosas }
162f0984d40SFabiano Rosas
163f0984d40SFabiano Rosas /* Silently ignore requests to clear D16-D31 if they don't exist */
164f0984d40SFabiano Rosas if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) {
165f0984d40SFabiano Rosas topreg = 31;
166f0984d40SFabiano Rosas }
167f0984d40SFabiano Rosas
168f0984d40SFabiano Rosas if (!vfp_access_check(s)) {
169f0984d40SFabiano Rosas return true;
170f0984d40SFabiano Rosas }
171f0984d40SFabiano Rosas
172f0984d40SFabiano Rosas /* Zero the Sregs from btmreg to topreg inclusive. */
173f0984d40SFabiano Rosas zero = tcg_constant_i64(0);
174f0984d40SFabiano Rosas if (btmreg & 1) {
175f0984d40SFabiano Rosas write_neon_element64(zero, btmreg >> 1, 1, MO_32);
176f0984d40SFabiano Rosas btmreg++;
177f0984d40SFabiano Rosas }
178f0984d40SFabiano Rosas for (; btmreg + 1 <= topreg; btmreg += 2) {
179f0984d40SFabiano Rosas write_neon_element64(zero, btmreg >> 1, 0, MO_64);
180f0984d40SFabiano Rosas }
181f0984d40SFabiano Rosas if (btmreg == topreg) {
182f0984d40SFabiano Rosas write_neon_element64(zero, btmreg >> 1, 0, MO_32);
183f0984d40SFabiano Rosas btmreg++;
184f0984d40SFabiano Rosas }
185f0984d40SFabiano Rosas assert(btmreg == topreg + 1);
186f0984d40SFabiano Rosas if (dc_isar_feature(aa32_mve, s)) {
187f0984d40SFabiano Rosas store_cpu_field(tcg_constant_i32(0), v7m.vpr);
188f0984d40SFabiano Rosas }
189f0984d40SFabiano Rosas
190f0984d40SFabiano Rosas clear_eci_state(s);
191f0984d40SFabiano Rosas return true;
192f0984d40SFabiano Rosas }
193f0984d40SFabiano Rosas
194f0984d40SFabiano Rosas /*
195f0984d40SFabiano Rosas * M-profile provides two different sets of instructions that can
196f0984d40SFabiano Rosas * access floating point system registers: VMSR/VMRS (which move
197f0984d40SFabiano Rosas * to/from a general purpose register) and VLDR/VSTR sysreg (which
198f0984d40SFabiano Rosas * move directly to/from memory). In some cases there are also side
199f0984d40SFabiano Rosas * effects which must happen after any write to memory (which could
200f0984d40SFabiano Rosas * cause an exception). So we implement the common logic for the
201f0984d40SFabiano Rosas * sysreg access in gen_M_fp_sysreg_write() and gen_M_fp_sysreg_read(),
202f0984d40SFabiano Rosas * which take pointers to callback functions which will perform the
203f0984d40SFabiano Rosas * actual "read/write general purpose register" and "read/write
204f0984d40SFabiano Rosas * memory" operations.
205f0984d40SFabiano Rosas */
206f0984d40SFabiano Rosas
207f0984d40SFabiano Rosas /*
208f0984d40SFabiano Rosas * Emit code to store the sysreg to its final destination; frees the
209f0984d40SFabiano Rosas * TCG temp 'value' it is passed. do_access is true to do the store,
210f0984d40SFabiano Rosas * and false to skip it and only perform side-effects like base
211f0984d40SFabiano Rosas * register writeback.
212f0984d40SFabiano Rosas */
213f0984d40SFabiano Rosas typedef void fp_sysreg_storefn(DisasContext *s, void *opaque, TCGv_i32 value,
214f0984d40SFabiano Rosas bool do_access);
215f0984d40SFabiano Rosas /*
216f0984d40SFabiano Rosas * Emit code to load the value to be copied to the sysreg; returns
217f0984d40SFabiano Rosas * a new TCG temporary. do_access is true to do the store,
218f0984d40SFabiano Rosas * and false to skip it and only perform side-effects like base
219f0984d40SFabiano Rosas * register writeback.
220f0984d40SFabiano Rosas */
221f0984d40SFabiano Rosas typedef TCGv_i32 fp_sysreg_loadfn(DisasContext *s, void *opaque,
222f0984d40SFabiano Rosas bool do_access);
223f0984d40SFabiano Rosas
224f0984d40SFabiano Rosas /* Common decode/access checks for fp sysreg read/write */
225f0984d40SFabiano Rosas typedef enum FPSysRegCheckResult {
226f0984d40SFabiano Rosas FPSysRegCheckFailed, /* caller should return false */
227f0984d40SFabiano Rosas FPSysRegCheckDone, /* caller should return true */
228f0984d40SFabiano Rosas FPSysRegCheckContinue, /* caller should continue generating code */
229f0984d40SFabiano Rosas } FPSysRegCheckResult;
230f0984d40SFabiano Rosas
fp_sysreg_checks(DisasContext * s,int regno)231f0984d40SFabiano Rosas static FPSysRegCheckResult fp_sysreg_checks(DisasContext *s, int regno)
232f0984d40SFabiano Rosas {
233f0984d40SFabiano Rosas if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) {
234f0984d40SFabiano Rosas return FPSysRegCheckFailed;
235f0984d40SFabiano Rosas }
236f0984d40SFabiano Rosas
237f0984d40SFabiano Rosas switch (regno) {
238f0984d40SFabiano Rosas case ARM_VFP_FPSCR:
239f0984d40SFabiano Rosas case QEMU_VFP_FPSCR_NZCV:
240f0984d40SFabiano Rosas break;
241f0984d40SFabiano Rosas case ARM_VFP_FPSCR_NZCVQC:
242f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
243f0984d40SFabiano Rosas return FPSysRegCheckFailed;
244f0984d40SFabiano Rosas }
245f0984d40SFabiano Rosas break;
246f0984d40SFabiano Rosas case ARM_VFP_FPCXT_S:
247f0984d40SFabiano Rosas case ARM_VFP_FPCXT_NS:
248f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
249f0984d40SFabiano Rosas return FPSysRegCheckFailed;
250f0984d40SFabiano Rosas }
251f0984d40SFabiano Rosas if (!s->v8m_secure) {
252f0984d40SFabiano Rosas return FPSysRegCheckFailed;
253f0984d40SFabiano Rosas }
254f0984d40SFabiano Rosas break;
255f0984d40SFabiano Rosas case ARM_VFP_VPR:
256f0984d40SFabiano Rosas case ARM_VFP_P0:
257f0984d40SFabiano Rosas if (!dc_isar_feature(aa32_mve, s)) {
258f0984d40SFabiano Rosas return FPSysRegCheckFailed;
259f0984d40SFabiano Rosas }
260f0984d40SFabiano Rosas break;
261f0984d40SFabiano Rosas default:
262f0984d40SFabiano Rosas return FPSysRegCheckFailed;
263f0984d40SFabiano Rosas }
264f0984d40SFabiano Rosas
265f0984d40SFabiano Rosas /*
266f0984d40SFabiano Rosas * FPCXT_NS is a special case: it has specific handling for
267f0984d40SFabiano Rosas * "current FP state is inactive", and must do the PreserveFPState()
268f0984d40SFabiano Rosas * but not the usual full set of actions done by ExecuteFPCheck().
269f0984d40SFabiano Rosas * So we don't call vfp_access_check() and the callers must handle this.
270f0984d40SFabiano Rosas */
271f0984d40SFabiano Rosas if (regno != ARM_VFP_FPCXT_NS && !vfp_access_check(s)) {
272f0984d40SFabiano Rosas return FPSysRegCheckDone;
273f0984d40SFabiano Rosas }
274f0984d40SFabiano Rosas return FPSysRegCheckContinue;
275f0984d40SFabiano Rosas }
276f0984d40SFabiano Rosas
gen_branch_fpInactive(DisasContext * s,TCGCond cond,TCGLabel * label)277f0984d40SFabiano Rosas static void gen_branch_fpInactive(DisasContext *s, TCGCond cond,
278f0984d40SFabiano Rosas TCGLabel *label)
279f0984d40SFabiano Rosas {
280f0984d40SFabiano Rosas /*
281f0984d40SFabiano Rosas * FPCXT_NS is a special case: it has specific handling for
282f0984d40SFabiano Rosas * "current FP state is inactive", and must do the PreserveFPState()
283f0984d40SFabiano Rosas * but not the usual full set of actions done by ExecuteFPCheck().
284f0984d40SFabiano Rosas * We don't have a TB flag that matches the fpInactive check, so we
285f0984d40SFabiano Rosas * do it at runtime as we don't expect FPCXT_NS accesses to be frequent.
286f0984d40SFabiano Rosas *
287f0984d40SFabiano Rosas * Emit code that checks fpInactive and does a conditional
288f0984d40SFabiano Rosas * branch to label based on it:
289f0984d40SFabiano Rosas * if cond is TCG_COND_NE then branch if fpInactive != 0 (ie if inactive)
290f0984d40SFabiano Rosas * if cond is TCG_COND_EQ then branch if fpInactive == 0 (ie if active)
291f0984d40SFabiano Rosas */
292f0984d40SFabiano Rosas assert(cond == TCG_COND_EQ || cond == TCG_COND_NE);
293f0984d40SFabiano Rosas
294f0984d40SFabiano Rosas /* fpInactive = FPCCR_NS.ASPEN == 1 && CONTROL.FPCA == 0 */
295f0984d40SFabiano Rosas TCGv_i32 aspen, fpca;
296f0984d40SFabiano Rosas aspen = load_cpu_field(v7m.fpccr[M_REG_NS]);
297f0984d40SFabiano Rosas fpca = load_cpu_field(v7m.control[M_REG_S]);
298f0984d40SFabiano Rosas tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
299f0984d40SFabiano Rosas tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
300f0984d40SFabiano Rosas tcg_gen_andi_i32(fpca, fpca, R_V7M_CONTROL_FPCA_MASK);
301f0984d40SFabiano Rosas tcg_gen_or_i32(fpca, fpca, aspen);
302f0984d40SFabiano Rosas tcg_gen_brcondi_i32(tcg_invert_cond(cond), fpca, 0, label);
303f0984d40SFabiano Rosas }
304f0984d40SFabiano Rosas
gen_M_fp_sysreg_write(DisasContext * s,int regno,fp_sysreg_loadfn * loadfn,void * opaque)305f0984d40SFabiano Rosas static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
306f0984d40SFabiano Rosas fp_sysreg_loadfn *loadfn,
307f0984d40SFabiano Rosas void *opaque)
308f0984d40SFabiano Rosas {
309f0984d40SFabiano Rosas /* Do a write to an M-profile floating point system register */
310f0984d40SFabiano Rosas TCGv_i32 tmp;
311f0984d40SFabiano Rosas TCGLabel *lab_end = NULL;
312f0984d40SFabiano Rosas
313f0984d40SFabiano Rosas switch (fp_sysreg_checks(s, regno)) {
314f0984d40SFabiano Rosas case FPSysRegCheckFailed:
315f0984d40SFabiano Rosas return false;
316f0984d40SFabiano Rosas case FPSysRegCheckDone:
317f0984d40SFabiano Rosas return true;
318f0984d40SFabiano Rosas case FPSysRegCheckContinue:
319f0984d40SFabiano Rosas break;
320f0984d40SFabiano Rosas }
321f0984d40SFabiano Rosas
322f0984d40SFabiano Rosas switch (regno) {
323f0984d40SFabiano Rosas case ARM_VFP_FPSCR:
324f0984d40SFabiano Rosas tmp = loadfn(s, opaque, true);
325ad75a51eSRichard Henderson gen_helper_vfp_set_fpscr(tcg_env, tmp);
326f0984d40SFabiano Rosas gen_lookup_tb(s);
327f0984d40SFabiano Rosas break;
328f0984d40SFabiano Rosas case ARM_VFP_FPSCR_NZCVQC:
329f0984d40SFabiano Rosas {
330f0984d40SFabiano Rosas TCGv_i32 fpscr;
331f0984d40SFabiano Rosas tmp = loadfn(s, opaque, true);
332f0984d40SFabiano Rosas if (dc_isar_feature(aa32_mve, s)) {
333f0984d40SFabiano Rosas /* QC is only present for MVE; otherwise RES0 */
334f0984d40SFabiano Rosas TCGv_i32 qc = tcg_temp_new_i32();
335*a26db547SPeter Maydell tcg_gen_andi_i32(qc, tmp, FPSR_QC);
336f0984d40SFabiano Rosas /*
337f0984d40SFabiano Rosas * The 4 vfp.qc[] fields need only be "zero" vs "non-zero";
338f0984d40SFabiano Rosas * here writing the same value into all elements is simplest.
339f0984d40SFabiano Rosas */
340f0984d40SFabiano Rosas tcg_gen_gvec_dup_i32(MO_32, offsetof(CPUARMState, vfp.qc),
341f0984d40SFabiano Rosas 16, 16, qc);
342f0984d40SFabiano Rosas }
343*a26db547SPeter Maydell tcg_gen_andi_i32(tmp, tmp, FPSR_NZCV_MASK);
344ce07ea61SPeter Maydell fpscr = load_cpu_field_low32(vfp.fpsr);
345*a26db547SPeter Maydell tcg_gen_andi_i32(fpscr, fpscr, ~FPSR_NZCV_MASK);
346f0984d40SFabiano Rosas tcg_gen_or_i32(fpscr, fpscr, tmp);
347ce07ea61SPeter Maydell store_cpu_field_low32(fpscr, vfp.fpsr);
348f0984d40SFabiano Rosas break;
349f0984d40SFabiano Rosas }
350f0984d40SFabiano Rosas case ARM_VFP_FPCXT_NS:
351f0984d40SFabiano Rosas {
352f0984d40SFabiano Rosas TCGLabel *lab_active = gen_new_label();
353f0984d40SFabiano Rosas
354f0984d40SFabiano Rosas lab_end = gen_new_label();
355f0984d40SFabiano Rosas gen_branch_fpInactive(s, TCG_COND_EQ, lab_active);
356f0984d40SFabiano Rosas /*
357f0984d40SFabiano Rosas * fpInactive case: write is a NOP, so only do side effects
358f0984d40SFabiano Rosas * like register writeback before we branch to end
359f0984d40SFabiano Rosas */
360f0984d40SFabiano Rosas loadfn(s, opaque, false);
361f0984d40SFabiano Rosas tcg_gen_br(lab_end);
362f0984d40SFabiano Rosas
363f0984d40SFabiano Rosas gen_set_label(lab_active);
364f0984d40SFabiano Rosas /*
365f0984d40SFabiano Rosas * !fpInactive: if FPU disabled, take NOCP exception;
366f0984d40SFabiano Rosas * otherwise PreserveFPState(), and then FPCXT_NS writes
367f0984d40SFabiano Rosas * behave the same as FPCXT_S writes.
368f0984d40SFabiano Rosas */
369f0984d40SFabiano Rosas if (!vfp_access_check_m(s, true)) {
370f0984d40SFabiano Rosas /*
371f0984d40SFabiano Rosas * This was only a conditional exception, so override
372f0984d40SFabiano Rosas * gen_exception_insn_el()'s default to DISAS_NORETURN
373f0984d40SFabiano Rosas */
374f0984d40SFabiano Rosas s->base.is_jmp = DISAS_NEXT;
375f0984d40SFabiano Rosas break;
376f0984d40SFabiano Rosas }
377f0984d40SFabiano Rosas }
378f0984d40SFabiano Rosas /* fall through */
379f0984d40SFabiano Rosas case ARM_VFP_FPCXT_S:
380f0984d40SFabiano Rosas {
381f0984d40SFabiano Rosas TCGv_i32 sfpa, control;
382f0984d40SFabiano Rosas /*
383f0984d40SFabiano Rosas * Set FPSCR and CONTROL.SFPA from value; the new FPSCR takes
384f0984d40SFabiano Rosas * bits [27:0] from value and zeroes bits [31:28].
385f0984d40SFabiano Rosas */
386f0984d40SFabiano Rosas tmp = loadfn(s, opaque, true);
387f0984d40SFabiano Rosas sfpa = tcg_temp_new_i32();
388f0984d40SFabiano Rosas tcg_gen_shri_i32(sfpa, tmp, 31);
389f0984d40SFabiano Rosas control = load_cpu_field(v7m.control[M_REG_S]);
390f0984d40SFabiano Rosas tcg_gen_deposit_i32(control, control, sfpa,
391f0984d40SFabiano Rosas R_V7M_CONTROL_SFPA_SHIFT, 1);
392f0984d40SFabiano Rosas store_cpu_field(control, v7m.control[M_REG_S]);
393*a26db547SPeter Maydell tcg_gen_andi_i32(tmp, tmp, ~FPSR_NZCV_MASK);
394ad75a51eSRichard Henderson gen_helper_vfp_set_fpscr(tcg_env, tmp);
395f0984d40SFabiano Rosas s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
396f0984d40SFabiano Rosas break;
397f0984d40SFabiano Rosas }
398f0984d40SFabiano Rosas case ARM_VFP_VPR:
399f0984d40SFabiano Rosas /* Behaves as NOP if not privileged */
400f0984d40SFabiano Rosas if (IS_USER(s)) {
401f0984d40SFabiano Rosas loadfn(s, opaque, false);
402f0984d40SFabiano Rosas break;
403f0984d40SFabiano Rosas }
404f0984d40SFabiano Rosas tmp = loadfn(s, opaque, true);
405f0984d40SFabiano Rosas store_cpu_field(tmp, v7m.vpr);
406f0984d40SFabiano Rosas s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
407f0984d40SFabiano Rosas break;
408f0984d40SFabiano Rosas case ARM_VFP_P0:
409f0984d40SFabiano Rosas {
410f0984d40SFabiano Rosas TCGv_i32 vpr;
411f0984d40SFabiano Rosas tmp = loadfn(s, opaque, true);
412f0984d40SFabiano Rosas vpr = load_cpu_field(v7m.vpr);
413f0984d40SFabiano Rosas tcg_gen_deposit_i32(vpr, vpr, tmp,
414f0984d40SFabiano Rosas R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH);
415f0984d40SFabiano Rosas store_cpu_field(vpr, v7m.vpr);
416f0984d40SFabiano Rosas s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
417f0984d40SFabiano Rosas break;
418f0984d40SFabiano Rosas }
419f0984d40SFabiano Rosas default:
420f0984d40SFabiano Rosas g_assert_not_reached();
421f0984d40SFabiano Rosas }
422f0984d40SFabiano Rosas if (lab_end) {
423f0984d40SFabiano Rosas gen_set_label(lab_end);
424f0984d40SFabiano Rosas }
425f0984d40SFabiano Rosas return true;
426f0984d40SFabiano Rosas }
427f0984d40SFabiano Rosas
gen_M_fp_sysreg_read(DisasContext * s,int regno,fp_sysreg_storefn * storefn,void * opaque)428f0984d40SFabiano Rosas static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
429f0984d40SFabiano Rosas fp_sysreg_storefn *storefn,
430f0984d40SFabiano Rosas void *opaque)
431f0984d40SFabiano Rosas {
432f0984d40SFabiano Rosas /* Do a read from an M-profile floating point system register */
433f0984d40SFabiano Rosas TCGv_i32 tmp;
434f0984d40SFabiano Rosas TCGLabel *lab_end = NULL;
435f0984d40SFabiano Rosas bool lookup_tb = false;
436f0984d40SFabiano Rosas
437f0984d40SFabiano Rosas switch (fp_sysreg_checks(s, regno)) {
438f0984d40SFabiano Rosas case FPSysRegCheckFailed:
439f0984d40SFabiano Rosas return false;
440f0984d40SFabiano Rosas case FPSysRegCheckDone:
441f0984d40SFabiano Rosas return true;
442f0984d40SFabiano Rosas case FPSysRegCheckContinue:
443f0984d40SFabiano Rosas break;
444f0984d40SFabiano Rosas }
445f0984d40SFabiano Rosas
446f0984d40SFabiano Rosas if (regno == ARM_VFP_FPSCR_NZCVQC && !dc_isar_feature(aa32_mve, s)) {
447f0984d40SFabiano Rosas /* QC is RES0 without MVE, so NZCVQC simplifies to NZCV */
448f0984d40SFabiano Rosas regno = QEMU_VFP_FPSCR_NZCV;
449f0984d40SFabiano Rosas }
450f0984d40SFabiano Rosas
451f0984d40SFabiano Rosas switch (regno) {
452f0984d40SFabiano Rosas case ARM_VFP_FPSCR:
453f0984d40SFabiano Rosas tmp = tcg_temp_new_i32();
454ad75a51eSRichard Henderson gen_helper_vfp_get_fpscr(tmp, tcg_env);
455f0984d40SFabiano Rosas storefn(s, opaque, tmp, true);
456f0984d40SFabiano Rosas break;
457f0984d40SFabiano Rosas case ARM_VFP_FPSCR_NZCVQC:
458f0984d40SFabiano Rosas tmp = tcg_temp_new_i32();
459ad75a51eSRichard Henderson gen_helper_vfp_get_fpscr(tmp, tcg_env);
460*a26db547SPeter Maydell tcg_gen_andi_i32(tmp, tmp, FPSR_NZCVQC_MASK);
461f0984d40SFabiano Rosas storefn(s, opaque, tmp, true);
462f0984d40SFabiano Rosas break;
463f0984d40SFabiano Rosas case QEMU_VFP_FPSCR_NZCV:
464f0984d40SFabiano Rosas /*
465f0984d40SFabiano Rosas * Read just NZCV; this is a special case to avoid the
466f0984d40SFabiano Rosas * helper call for the "VMRS to CPSR.NZCV" insn.
467f0984d40SFabiano Rosas */
468ce07ea61SPeter Maydell tmp = load_cpu_field_low32(vfp.fpsr);
469*a26db547SPeter Maydell tcg_gen_andi_i32(tmp, tmp, FPSR_NZCV_MASK);
470f0984d40SFabiano Rosas storefn(s, opaque, tmp, true);
471f0984d40SFabiano Rosas break;
472f0984d40SFabiano Rosas case ARM_VFP_FPCXT_S:
473f0984d40SFabiano Rosas {
474f0984d40SFabiano Rosas TCGv_i32 control, sfpa, fpscr;
475f0984d40SFabiano Rosas /* Bits [27:0] from FPSCR, bit [31] from CONTROL.SFPA */
476f0984d40SFabiano Rosas tmp = tcg_temp_new_i32();
477f0984d40SFabiano Rosas sfpa = tcg_temp_new_i32();
478ad75a51eSRichard Henderson gen_helper_vfp_get_fpscr(tmp, tcg_env);
479*a26db547SPeter Maydell tcg_gen_andi_i32(tmp, tmp, ~FPSR_NZCV_MASK);
480f0984d40SFabiano Rosas control = load_cpu_field(v7m.control[M_REG_S]);
481f0984d40SFabiano Rosas tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK);
482f0984d40SFabiano Rosas tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT);
483f0984d40SFabiano Rosas tcg_gen_or_i32(tmp, tmp, sfpa);
484f0984d40SFabiano Rosas /*
485f0984d40SFabiano Rosas * Store result before updating FPSCR etc, in case
486f0984d40SFabiano Rosas * it is a memory write which causes an exception.
487f0984d40SFabiano Rosas */
488f0984d40SFabiano Rosas storefn(s, opaque, tmp, true);
489f0984d40SFabiano Rosas /*
490f0984d40SFabiano Rosas * Now we must reset FPSCR from FPDSCR_NS, and clear
491f0984d40SFabiano Rosas * CONTROL.SFPA; so we'll end the TB here.
492f0984d40SFabiano Rosas */
493f0984d40SFabiano Rosas tcg_gen_andi_i32(control, control, ~R_V7M_CONTROL_SFPA_MASK);
494f0984d40SFabiano Rosas store_cpu_field(control, v7m.control[M_REG_S]);
495f0984d40SFabiano Rosas fpscr = load_cpu_field(v7m.fpdscr[M_REG_NS]);
496ad75a51eSRichard Henderson gen_helper_vfp_set_fpscr(tcg_env, fpscr);
497f0984d40SFabiano Rosas lookup_tb = true;
498f0984d40SFabiano Rosas break;
499f0984d40SFabiano Rosas }
500f0984d40SFabiano Rosas case ARM_VFP_FPCXT_NS:
501f0984d40SFabiano Rosas {
502f0984d40SFabiano Rosas TCGv_i32 control, sfpa, fpscr, fpdscr;
503f0984d40SFabiano Rosas TCGLabel *lab_active = gen_new_label();
504f0984d40SFabiano Rosas
505f0984d40SFabiano Rosas lookup_tb = true;
506f0984d40SFabiano Rosas
507f0984d40SFabiano Rosas gen_branch_fpInactive(s, TCG_COND_EQ, lab_active);
508f0984d40SFabiano Rosas /* fpInactive case: reads as FPDSCR_NS */
509d54deb2aSPhilippe Mathieu-Daudé tmp = load_cpu_field(v7m.fpdscr[M_REG_NS]);
510f0984d40SFabiano Rosas storefn(s, opaque, tmp, true);
511f0984d40SFabiano Rosas lab_end = gen_new_label();
512f0984d40SFabiano Rosas tcg_gen_br(lab_end);
513f0984d40SFabiano Rosas
514f0984d40SFabiano Rosas gen_set_label(lab_active);
515f0984d40SFabiano Rosas /*
516f0984d40SFabiano Rosas * !fpInactive: if FPU disabled, take NOCP exception;
517f0984d40SFabiano Rosas * otherwise PreserveFPState(), and then FPCXT_NS
518f0984d40SFabiano Rosas * reads the same as FPCXT_S.
519f0984d40SFabiano Rosas */
520f0984d40SFabiano Rosas if (!vfp_access_check_m(s, true)) {
521f0984d40SFabiano Rosas /*
522f0984d40SFabiano Rosas * This was only a conditional exception, so override
523f0984d40SFabiano Rosas * gen_exception_insn_el()'s default to DISAS_NORETURN
524f0984d40SFabiano Rosas */
525f0984d40SFabiano Rosas s->base.is_jmp = DISAS_NEXT;
526f0984d40SFabiano Rosas break;
527f0984d40SFabiano Rosas }
528f0984d40SFabiano Rosas tmp = tcg_temp_new_i32();
529f0984d40SFabiano Rosas sfpa = tcg_temp_new_i32();
530f0984d40SFabiano Rosas fpscr = tcg_temp_new_i32();
531ad75a51eSRichard Henderson gen_helper_vfp_get_fpscr(fpscr, tcg_env);
532*a26db547SPeter Maydell tcg_gen_andi_i32(tmp, fpscr, ~FPSR_NZCV_MASK);
533f0984d40SFabiano Rosas control = load_cpu_field(v7m.control[M_REG_S]);
534f0984d40SFabiano Rosas tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK);
535f0984d40SFabiano Rosas tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT);
536f0984d40SFabiano Rosas tcg_gen_or_i32(tmp, tmp, sfpa);
537f0984d40SFabiano Rosas /* Store result before updating FPSCR, in case it faults */
538f0984d40SFabiano Rosas storefn(s, opaque, tmp, true);
539f0984d40SFabiano Rosas /* If SFPA is zero then set FPSCR from FPDSCR_NS */
540f0984d40SFabiano Rosas fpdscr = load_cpu_field(v7m.fpdscr[M_REG_NS]);
541f0984d40SFabiano Rosas tcg_gen_movcond_i32(TCG_COND_EQ, fpscr, sfpa, tcg_constant_i32(0),
542f0984d40SFabiano Rosas fpdscr, fpscr);
543ad75a51eSRichard Henderson gen_helper_vfp_set_fpscr(tcg_env, fpscr);
544f0984d40SFabiano Rosas break;
545f0984d40SFabiano Rosas }
546f0984d40SFabiano Rosas case ARM_VFP_VPR:
547f0984d40SFabiano Rosas /* Behaves as NOP if not privileged */
548f0984d40SFabiano Rosas if (IS_USER(s)) {
549f0984d40SFabiano Rosas storefn(s, opaque, NULL, false);
550f0984d40SFabiano Rosas break;
551f0984d40SFabiano Rosas }
552f0984d40SFabiano Rosas tmp = load_cpu_field(v7m.vpr);
553f0984d40SFabiano Rosas storefn(s, opaque, tmp, true);
554f0984d40SFabiano Rosas break;
555f0984d40SFabiano Rosas case ARM_VFP_P0:
556f0984d40SFabiano Rosas tmp = load_cpu_field(v7m.vpr);
557f0984d40SFabiano Rosas tcg_gen_extract_i32(tmp, tmp, R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH);
558f0984d40SFabiano Rosas storefn(s, opaque, tmp, true);
559f0984d40SFabiano Rosas break;
560f0984d40SFabiano Rosas default:
561f0984d40SFabiano Rosas g_assert_not_reached();
562f0984d40SFabiano Rosas }
563f0984d40SFabiano Rosas
564f0984d40SFabiano Rosas if (lab_end) {
565f0984d40SFabiano Rosas gen_set_label(lab_end);
566f0984d40SFabiano Rosas }
567f0984d40SFabiano Rosas if (lookup_tb) {
568f0984d40SFabiano Rosas gen_lookup_tb(s);
569f0984d40SFabiano Rosas }
570f0984d40SFabiano Rosas return true;
571f0984d40SFabiano Rosas }
572f0984d40SFabiano Rosas
fp_sysreg_to_gpr(DisasContext * s,void * opaque,TCGv_i32 value,bool do_access)573f0984d40SFabiano Rosas static void fp_sysreg_to_gpr(DisasContext *s, void *opaque, TCGv_i32 value,
574f0984d40SFabiano Rosas bool do_access)
575f0984d40SFabiano Rosas {
576f0984d40SFabiano Rosas arg_VMSR_VMRS *a = opaque;
577f0984d40SFabiano Rosas
578f0984d40SFabiano Rosas if (!do_access) {
579f0984d40SFabiano Rosas return;
580f0984d40SFabiano Rosas }
581f0984d40SFabiano Rosas
582f0984d40SFabiano Rosas if (a->rt == 15) {
583f0984d40SFabiano Rosas /* Set the 4 flag bits in the CPSR */
584f0984d40SFabiano Rosas gen_set_nzcv(value);
585f0984d40SFabiano Rosas } else {
586f0984d40SFabiano Rosas store_reg(s, a->rt, value);
587f0984d40SFabiano Rosas }
588f0984d40SFabiano Rosas }
589f0984d40SFabiano Rosas
gpr_to_fp_sysreg(DisasContext * s,void * opaque,bool do_access)590f0984d40SFabiano Rosas static TCGv_i32 gpr_to_fp_sysreg(DisasContext *s, void *opaque, bool do_access)
591f0984d40SFabiano Rosas {
592f0984d40SFabiano Rosas arg_VMSR_VMRS *a = opaque;
593f0984d40SFabiano Rosas
594f0984d40SFabiano Rosas if (!do_access) {
595f0984d40SFabiano Rosas return NULL;
596f0984d40SFabiano Rosas }
597f0984d40SFabiano Rosas return load_reg(s, a->rt);
598f0984d40SFabiano Rosas }
599f0984d40SFabiano Rosas
trans_VMSR_VMRS(DisasContext * s,arg_VMSR_VMRS * a)600f0984d40SFabiano Rosas static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
601f0984d40SFabiano Rosas {
602f0984d40SFabiano Rosas /*
603f0984d40SFabiano Rosas * Accesses to R15 are UNPREDICTABLE; we choose to undef.
604f0984d40SFabiano Rosas * FPSCR -> r15 is a special case which writes to the PSR flags;
605f0984d40SFabiano Rosas * set a->reg to a special value to tell gen_M_fp_sysreg_read()
606f0984d40SFabiano Rosas * we only care about the top 4 bits of FPSCR there.
607f0984d40SFabiano Rosas */
608f0984d40SFabiano Rosas if (a->rt == 15) {
609f0984d40SFabiano Rosas if (a->l && a->reg == ARM_VFP_FPSCR) {
610f0984d40SFabiano Rosas a->reg = QEMU_VFP_FPSCR_NZCV;
611f0984d40SFabiano Rosas } else {
612f0984d40SFabiano Rosas return false;
613f0984d40SFabiano Rosas }
614f0984d40SFabiano Rosas }
615f0984d40SFabiano Rosas
616f0984d40SFabiano Rosas if (a->l) {
617f0984d40SFabiano Rosas /* VMRS, move FP system register to gp register */
618f0984d40SFabiano Rosas return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_gpr, a);
619f0984d40SFabiano Rosas } else {
620f0984d40SFabiano Rosas /* VMSR, move gp register to FP system register */
621f0984d40SFabiano Rosas return gen_M_fp_sysreg_write(s, a->reg, gpr_to_fp_sysreg, a);
622f0984d40SFabiano Rosas }
623f0984d40SFabiano Rosas }
624f0984d40SFabiano Rosas
fp_sysreg_to_memory(DisasContext * s,void * opaque,TCGv_i32 value,bool do_access)625f0984d40SFabiano Rosas static void fp_sysreg_to_memory(DisasContext *s, void *opaque, TCGv_i32 value,
626f0984d40SFabiano Rosas bool do_access)
627f0984d40SFabiano Rosas {
628f0984d40SFabiano Rosas arg_vldr_sysreg *a = opaque;
629f0984d40SFabiano Rosas uint32_t offset = a->imm;
630f0984d40SFabiano Rosas TCGv_i32 addr;
631f0984d40SFabiano Rosas
632f0984d40SFabiano Rosas if (!a->a) {
633f0984d40SFabiano Rosas offset = -offset;
634f0984d40SFabiano Rosas }
635f0984d40SFabiano Rosas
636f0984d40SFabiano Rosas if (!do_access && !a->w) {
637f0984d40SFabiano Rosas return;
638f0984d40SFabiano Rosas }
639f0984d40SFabiano Rosas
640f0984d40SFabiano Rosas addr = load_reg(s, a->rn);
641f0984d40SFabiano Rosas if (a->p) {
642f0984d40SFabiano Rosas tcg_gen_addi_i32(addr, addr, offset);
643f0984d40SFabiano Rosas }
644f0984d40SFabiano Rosas
645f0984d40SFabiano Rosas if (s->v8m_stackcheck && a->rn == 13 && a->w) {
646ad75a51eSRichard Henderson gen_helper_v8m_stackcheck(tcg_env, addr);
647f0984d40SFabiano Rosas }
648f0984d40SFabiano Rosas
649f0984d40SFabiano Rosas if (do_access) {
650f0984d40SFabiano Rosas gen_aa32_st_i32(s, value, addr, get_mem_index(s),
651f0984d40SFabiano Rosas MO_UL | MO_ALIGN | s->be_data);
652f0984d40SFabiano Rosas }
653f0984d40SFabiano Rosas
654f0984d40SFabiano Rosas if (a->w) {
655f0984d40SFabiano Rosas /* writeback */
656f0984d40SFabiano Rosas if (!a->p) {
657f0984d40SFabiano Rosas tcg_gen_addi_i32(addr, addr, offset);
658f0984d40SFabiano Rosas }
659f0984d40SFabiano Rosas store_reg(s, a->rn, addr);
660f0984d40SFabiano Rosas }
661f0984d40SFabiano Rosas }
662f0984d40SFabiano Rosas
memory_to_fp_sysreg(DisasContext * s,void * opaque,bool do_access)663f0984d40SFabiano Rosas static TCGv_i32 memory_to_fp_sysreg(DisasContext *s, void *opaque,
664f0984d40SFabiano Rosas bool do_access)
665f0984d40SFabiano Rosas {
666f0984d40SFabiano Rosas arg_vldr_sysreg *a = opaque;
667f0984d40SFabiano Rosas uint32_t offset = a->imm;
668f0984d40SFabiano Rosas TCGv_i32 addr;
669f0984d40SFabiano Rosas TCGv_i32 value = NULL;
670f0984d40SFabiano Rosas
671f0984d40SFabiano Rosas if (!a->a) {
672f0984d40SFabiano Rosas offset = -offset;
673f0984d40SFabiano Rosas }
674f0984d40SFabiano Rosas
675f0984d40SFabiano Rosas if (!do_access && !a->w) {
676f0984d40SFabiano Rosas return NULL;
677f0984d40SFabiano Rosas }
678f0984d40SFabiano Rosas
679f0984d40SFabiano Rosas addr = load_reg(s, a->rn);
680f0984d40SFabiano Rosas if (a->p) {
681f0984d40SFabiano Rosas tcg_gen_addi_i32(addr, addr, offset);
682f0984d40SFabiano Rosas }
683f0984d40SFabiano Rosas
684f0984d40SFabiano Rosas if (s->v8m_stackcheck && a->rn == 13 && a->w) {
685ad75a51eSRichard Henderson gen_helper_v8m_stackcheck(tcg_env, addr);
686f0984d40SFabiano Rosas }
687f0984d40SFabiano Rosas
688f0984d40SFabiano Rosas if (do_access) {
689f0984d40SFabiano Rosas value = tcg_temp_new_i32();
690f0984d40SFabiano Rosas gen_aa32_ld_i32(s, value, addr, get_mem_index(s),
691f0984d40SFabiano Rosas MO_UL | MO_ALIGN | s->be_data);
692f0984d40SFabiano Rosas }
693f0984d40SFabiano Rosas
694f0984d40SFabiano Rosas if (a->w) {
695f0984d40SFabiano Rosas /* writeback */
696f0984d40SFabiano Rosas if (!a->p) {
697f0984d40SFabiano Rosas tcg_gen_addi_i32(addr, addr, offset);
698f0984d40SFabiano Rosas }
699f0984d40SFabiano Rosas store_reg(s, a->rn, addr);
700f0984d40SFabiano Rosas }
701f0984d40SFabiano Rosas return value;
702f0984d40SFabiano Rosas }
703f0984d40SFabiano Rosas
trans_VLDR_sysreg(DisasContext * s,arg_vldr_sysreg * a)704f0984d40SFabiano Rosas static bool trans_VLDR_sysreg(DisasContext *s, arg_vldr_sysreg *a)
705f0984d40SFabiano Rosas {
706f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
707f0984d40SFabiano Rosas return false;
708f0984d40SFabiano Rosas }
709f0984d40SFabiano Rosas if (a->rn == 15) {
710f0984d40SFabiano Rosas return false;
711f0984d40SFabiano Rosas }
712f0984d40SFabiano Rosas return gen_M_fp_sysreg_write(s, a->reg, memory_to_fp_sysreg, a);
713f0984d40SFabiano Rosas }
714f0984d40SFabiano Rosas
trans_VSTR_sysreg(DisasContext * s,arg_vldr_sysreg * a)715f0984d40SFabiano Rosas static bool trans_VSTR_sysreg(DisasContext *s, arg_vldr_sysreg *a)
716f0984d40SFabiano Rosas {
717f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
718f0984d40SFabiano Rosas return false;
719f0984d40SFabiano Rosas }
720f0984d40SFabiano Rosas if (a->rn == 15) {
721f0984d40SFabiano Rosas return false;
722f0984d40SFabiano Rosas }
723f0984d40SFabiano Rosas return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_memory, a);
724f0984d40SFabiano Rosas }
725f0984d40SFabiano Rosas
trans_NOCP(DisasContext * s,arg_nocp * a)726f0984d40SFabiano Rosas static bool trans_NOCP(DisasContext *s, arg_nocp *a)
727f0984d40SFabiano Rosas {
728f0984d40SFabiano Rosas /*
729f0984d40SFabiano Rosas * Handle M-profile early check for disabled coprocessor:
730f0984d40SFabiano Rosas * all we need to do here is emit the NOCP exception if
731f0984d40SFabiano Rosas * the coprocessor is disabled. Otherwise we return false
732f0984d40SFabiano Rosas * and the real VFP/etc decode will handle the insn.
733f0984d40SFabiano Rosas */
734f0984d40SFabiano Rosas assert(arm_dc_feature(s, ARM_FEATURE_M));
735f0984d40SFabiano Rosas
736f0984d40SFabiano Rosas if (a->cp == 11) {
737f0984d40SFabiano Rosas a->cp = 10;
738f0984d40SFabiano Rosas }
739f0984d40SFabiano Rosas if (arm_dc_feature(s, ARM_FEATURE_V8_1M) &&
740f0984d40SFabiano Rosas (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) {
741f0984d40SFabiano Rosas /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
742f0984d40SFabiano Rosas a->cp = 10;
743f0984d40SFabiano Rosas }
744f0984d40SFabiano Rosas
745f0984d40SFabiano Rosas if (a->cp != 10) {
746f0984d40SFabiano Rosas gen_exception_insn(s, 0, EXCP_NOCP, syn_uncategorized());
747f0984d40SFabiano Rosas return true;
748f0984d40SFabiano Rosas }
749f0984d40SFabiano Rosas
750f0984d40SFabiano Rosas if (s->fp_excp_el != 0) {
751f0984d40SFabiano Rosas gen_exception_insn_el(s, 0, EXCP_NOCP,
752f0984d40SFabiano Rosas syn_uncategorized(), s->fp_excp_el);
753f0984d40SFabiano Rosas return true;
754f0984d40SFabiano Rosas }
755f0984d40SFabiano Rosas
756f0984d40SFabiano Rosas return false;
757f0984d40SFabiano Rosas }
758f0984d40SFabiano Rosas
trans_NOCP_8_1(DisasContext * s,arg_nocp * a)759f0984d40SFabiano Rosas static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a)
760f0984d40SFabiano Rosas {
761f0984d40SFabiano Rosas /* This range needs a coprocessor check for v8.1M and later only */
762f0984d40SFabiano Rosas if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
763f0984d40SFabiano Rosas return false;
764f0984d40SFabiano Rosas }
765f0984d40SFabiano Rosas return trans_NOCP(s, a);
766f0984d40SFabiano Rosas }
767