xref: /openbmc/qemu/target/arm/tcg/translate-m-nocp.c (revision 23901b2b721c0576007ab7580da8aa855d6042a9)
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